2 * cls_canprio.c -- Canprio classifier.
3 * Makes decisions accoring to controller area network (CAN) identifiers.
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
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
18 * Some function descriptions are heavily inspired by article "Linux Network
19 * Traffic Control -- Implementation Overview" by Werner Almesberger
22 * Implementation notes;
23 * parameter of functions named "base" is pointer to some parent element
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>
43 //--------------------------------------
45 /* Definition of Netlink messages */
50 TCA_CANPRIO_INV_EN, /* enable inverse rules */
53 #define TCA_CANPRIO_MAX (__TCA_CANPRIO_MAX - 1)
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 },
62 struct canprio_eff_item {
63 struct hlist_node list;
65 struct can_filter rule;
67 static DEFINE_SPINLOCK(canprio_match_eff_lock);
69 struct canprio_rules {
70 struct can_filter *rules_raw; /* Raw rules copied from netlink message;
71 Used for sending information to userspace
72 (when 'tc filter show' is invoked) */
73 DECLARE_BITMAP(match_sff, CAN_SFF_MASK + 1); /* For each SFF Can ID (11 bit)
74 there is one record in this bitfield */
75 struct hlist_head match_eff; /* List of EFF frames to match */
76 int inv_match_en; /* Inverted match flag */
84 struct list_head flist;
87 struct canprio_filter {
89 struct canprio_rules rules;
90 struct tcf_result res;
91 struct list_head link;
95 * ----------------------------------------------------------------------------
98 static void canprio_sff_match_add(struct canprio_filter *f, u32 canid, u32 mask)
102 printk("%s() invoked\n", __FUNCTION__);
103 mask &= CAN_SFF_MASK;
104 canid = canid & mask;
106 if (mask == CAN_SFF_MASK) {
107 set_bit(canid, f->rules.match_sff);
111 for (i = 0; i <= CAN_SFF_MASK; i++) {
112 if ((i & mask) == canid)
113 set_bit(i, f->rules.match_sff);
117 static int canprio_eff_match_add(struct canprio_filter *f, u32 canid, u32 mask)
119 struct canprio_eff_item *eff;
122 printk("%s() invoked\n", __FUNCTION__);
123 mask &= CAN_EFF_MASK;
124 canid = canid & mask;
126 eff = kmalloc(sizeof(struct canprio_eff_item), GFP_KERNEL);
130 spin_lock(&canprio_match_eff_lock);
132 eff->rule.can_id = canid;
133 eff->rule.can_mask = mask;
135 hlist_add_head_rcu(&eff->list, &f->rules.match_eff);
137 spin_unlock(&canprio_match_eff_lock);
143 * Extracts Can ID ot ouf the sk_buff structure.
145 static u32 canprio_get_id(struct sk_buff *skb)
147 /* Can ID is inside of data field */
148 struct can_frame *cf = (struct can_frame *)skb->data;
149 //canid_t canid = cf->canid;
151 return (u32)cf->can_id;
155 * Performs the classification. Iterates over all instances of filter
156 * checking for Can ID match.
158 * @skb: Socket buffer
160 * @res: Is used for setting Class ID as a result of classification
162 * Returns value relevant for policing. Used return values:
163 * TC_POLICE_OK if succesfully classified (without regard to policing rules)
164 * TC_POLICE_UNSPEC if no matching filter was found
166 static int canprio_classify(struct sk_buff *skb, struct tcf_proto *tp,
167 struct tcf_result *res)
169 struct canprio_head *head = (struct canprio_head *)tp->root;
170 struct canprio_filter *f;
173 printk(" canprio_classify() invoked\n");
174 canid = canprio_get_id(skb);
176 list_for_each_entry(f, &head->flist, link) {
178 printk(" canprio_classify() can ID of received frame = 0x%x\n", canid);
180 if (canid & CAN_EFF_FLAG) {
181 struct canprio_eff_item *effi;
182 struct hlist_node *next;
186 hlist_for_each_entry_rcu(effi, next, &f->rules.match_eff, list) {
187 if ((effi->rule.can_id ^ canid) & effi->rule.can_mask) {
195 match = test_bit(canid, f->rules.match_sff);
198 if (f->rules.inv_match_en)
204 printk( " canprio_classify() match ok: ID 0x%x\n", canid);
208 return TC_POLICE_UNSPEC;
214 static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f,
215 unsigned long base, struct nlattr **tb,
219 printk(" canprio_set_parms invoked\n");
221 if (tb[TCA_CANPRIO_CLASSID]) {
222 f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
223 bitmap_zero(f->rules.match_sff, CAN_SFF_MASK + 1);
224 INIT_HLIST_HEAD(&f->rules.match_eff);
226 tcf_bind_filter(tp, &f->res, base);
233 * Looks up a filter element by its handle and returns the internal
234 * filter ID (i.e. pointer)
236 static unsigned long canprio_get(struct tcf_proto *tp, u32 handle)
238 struct canprio_head *head = (struct canprio_head *)tp->root;
239 struct canprio_filter *f;
241 //printk("canprio_get(%d) invoked\n", handle);
245 //printk("[running for_each_entry]\n");
246 list_for_each_entry(f, &head->flist, link) {
247 //printk("[f->handle = %d]\n", f->handle);
248 if (f->handle == handle) {
249 //printk("found something\n");
250 return (unsigned long) f;
258 * Is invoked when a filter element previously referenced
259 * with get() is no longer used
261 static void canprio_put(struct tcf_proto *tp, unsigned long f)
266 static unsigned int canprio_gen_handle(struct tcf_proto *tp)
268 struct canprio_head *head = (struct canprio_head *)tp->root;
275 if ((head->hgenerator += 0x10000) == 0)
276 head->hgenerator = 0x10000;
278 h = head->hgenerator;
279 //if (canprio_get(tp, h) == 0)
281 tmp = canprio_get(tp, h);
282 //printk("___tried %d result %lu\n", h, tmp);
291 * Called for changing properties of an existing filter or after addition
292 * of a new filter to a class (by calling bind_tcf which binds an instance
293 * of a filter to the class).
295 * @tp: Structure representing instance of a filter.
296 * Part of a linked list of all filters.
299 * @tca: Messages passed through the Netlink from userspace.
302 static int canprio_change(struct tcf_proto *tp, unsigned long base, u32 handle,
303 struct nlattr **tca, unsigned long *arg)
306 struct canprio_head *head = (struct canprio_head *)tp->root;
307 struct canprio_filter *f = (struct canprio_filter *)*arg;
308 struct nlattr *tb[TCA_CANPRIO_MAX + 1];
309 struct can_filter *canprio_nl_rules;
312 printk(" canprio_change invoked\n");
314 if (tca[TCA_OPTIONS] == NULL)
317 /*Parses a stream of attributes and stores a pointer to each attribute in
318 the tb array accessible via the attribute type. Policy may be set to NULL
319 if no validation is required.*/
320 err = nla_parse_nested(tb, TCA_CANPRIO_MAX, tca[TCA_OPTIONS], canprio_policy);
324 //Change existing filter
326 if (handle && f->handle != handle)
328 return canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
333 f = kzalloc(sizeof(*f), GFP_KERNEL);
343 unsigned int i = 0x80000000;
345 if (++head->hgenerator == 0x7FFFFFFF)
346 head->hgenerator = 1;
347 } while (--i > 0 && canprio_get(tp, head->hgenerator));
350 pr_err("Insufficient number of handles\n");
354 handle = canprio_gen_handle(tp);
355 //printk("__new handle %d\n", handle);
357 //FIXME where is hgenerator initialized
361 //Configure newly created filter
362 err = canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
368 if (tb[TCA_CANPRIO_RULES] == NULL)
371 canprio_nl_rules = nla_data(tb[TCA_CANPRIO_RULES]);
372 f->rules.rules_count = (nla_len(tb[TCA_CANPRIO_RULES]) / sizeof(struct can_filter));
373 printk(" rules_count = %u\n", f->rules.rules_count);
375 err = -ENOMEM;//FIXME ENOBUFS?
376 f->rules.rules_raw = kzalloc(sizeof(struct can_filter) * f->rules.rules_count, GFP_KERNEL);
377 if (f->rules.rules_raw == NULL)
380 memcpy(f->rules.rules_raw, canprio_nl_rules,
381 sizeof(struct can_filter) * f->rules.rules_count);
383 for (i = 0; i < f->rules.rules_count; i++) {
384 /* FIXME: shouldn't use here the same logic as in
385 * can_rcv_filter() to filter for various combination
386 * of flags (EFF, RTR) */
387 if (canprio_nl_rules[i].can_id & CAN_EFF_FLAG) {
388 err = canprio_eff_match_add(f, canprio_nl_rules[i].can_id,
389 canprio_nl_rules[i].can_mask);
393 canprio_sff_match_add(f, canprio_nl_rules[i].can_id,
394 canprio_nl_rules[i].can_mask);
397 printk(" can ID to match = 0x%x with mask 0x%x\n",
398 canprio_nl_rules[i].can_id, canprio_nl_rules[i].can_mask);
401 f->rules.inv_match_en = 0;
402 if (tb[TCA_CANPRIO_INV_EN] != NULL)
403 f->rules.inv_match_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]);
405 //Add newly created filter to list of all filters
407 list_add(&f->link, &head->flist);
409 *arg = (unsigned long) f;
414 if (f->rules.rules_raw != NULL) //FIXME is ok?
415 kfree(f->rules.rules_raw);
417 if (*arg == 0UL && f)
424 static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f)
426 struct canprio_eff_item *effi;
427 struct hlist_node *p, *n;
431 tcf_unbind_filter(tp, &f->res);
432 hlist_for_each_entry_safe(effi, p, n, &(f->rules.match_eff), list) {
436 kfree(f->rules.rules_raw);
441 * Remove whole filter.
443 static void canprio_destroy(struct tcf_proto *tp)
445 struct canprio_head *head = tp->root;
446 struct canprio_filter *f, *n;
448 list_for_each_entry_safe(f, n, &head->flist, link) {
450 canprio_delete_filter(tp, f);
456 * Delete one instance of a filter.
458 static int canprio_delete(struct tcf_proto *tp, unsigned long arg)
460 struct canprio_head *head = (struct canprio_head *)tp->root;
461 struct canprio_filter *t;
462 struct canprio_filter *f = (struct canprio_filter *)arg;
464 rcu_barrier(); /* Wait for completion of call_rcu()'s */
466 list_for_each_entry(t, &head->flist, link)
471 canprio_delete_filter(tp, t);
482 static int canprio_init(struct tcf_proto *tp)
484 struct canprio_head *head;
485 //printk("tp = %p\n", tp);
486 printk(" canprio_init invoked\n");
488 head = kzalloc(sizeof(*head), GFP_KERNEL);
492 INIT_LIST_HEAD(&head->flist);
494 tp->protocol = htons(ETH_P_CAN); /* Work only on AF_CAN packets - not tested! */
500 * Iterates over all elements of a filter and invokes a callback function
501 * for each of them. This is used to obtain diagnostic data
503 static void canprio_walk(struct tcf_proto *tp, struct tcf_walker *arg)
505 struct canprio_head *head = (struct canprio_head *) tp->root;
506 struct canprio_filter *f;
508 printk("%s() invoked\n", __FUNCTION__);
510 list_for_each_entry(f, &head->flist, link) {
511 if (arg->count < arg->skip)
514 printk("calling canprio_dump()\n");
515 if (arg->fn(tp, (unsigned long) f, arg) < 0) {
525 * Returns diagnostic data for a filter or one of its elements.
527 static int canprio_dump(struct tcf_proto *tp, unsigned long fh,
528 struct sk_buff *skb, struct tcmsg *t)
530 struct canprio_filter *f = (struct canprio_filter *) fh;
533 printk("%s() invoked\n", __FUNCTION__);
538 t->tcm_handle = f->handle;
540 nest = nla_nest_start(skb, TCA_OPTIONS);
542 goto nla_put_failure;
545 NLA_PUT_U32(skb, TCA_CANPRIO_CLASSID, f->res.classid);
548 NLA_PUT(skb, TCA_CANPRIO_RULES, f->rules.rules_count *
549 sizeof(struct can_filter), f->rules.rules_raw);
550 printk(" sending %d rules.", f->rules.rules_count);
553 nla_nest_end(skb, nest);
558 nla_nest_cancel(skb, nest);
563 static struct tcf_proto_ops cls_canprio_ops __read_mostly = {
565 .classify = canprio_classify,
566 .init = canprio_init,
567 .destroy = canprio_destroy,
570 .change = canprio_change,
571 .delete = canprio_delete,
572 .walk = canprio_walk,
573 .dump = canprio_dump,
574 .owner = THIS_MODULE,
577 static int __init init_canprio(void)
579 printk("Canprio loaded\n");
580 return register_tcf_proto_ops(&cls_canprio_ops);
583 static void __exit exit_canprio(void)
585 printk("Canprio removed\n");
586 unregister_tcf_proto_ops(&cls_canprio_ops);
589 module_init(init_canprio);
590 module_exit(exit_canprio);
591 MODULE_LICENSE("GPL");
592 MODULE_AUTHOR(""); // FIXME
593 MODULE_DESCRIPTION("Controller Area Network can_id classifier");