1 /* cls_canprio.c -- Canprio classifier.
2 * Makes decisions accoring to Can IDs.
4 * Implementation notes;
5 * parameter of functions named "base" is pointer to some parent element
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 #include <linux/bitmap.h>
22 #include <linux/spinlock.h>
23 #include <linux/rcupdate.h>
25 //--------------------------------------
26 //FIXME put in some *.h file shared with userspace "tc"?
32 struct canprio_rule *canprio_rules;
33 int canprio_rules_count = 0;
34 //--------------------------------------
36 /* Definition of Netlink messages */
41 TCA_CANPRIO_INV_EN, /* enable inverse rules */
44 #define TCA_CANPRIO_MAX (__TCA_CANPRIO_MAX - 1)
46 static const struct nla_policy canprio_policy[TCA_CANPRIO_MAX + 1] = {
47 [TCA_CANPRIO_CLASSID] = { .type = NLA_U32 },
48 //FIXME Be aware of possible problems with 64bit kernel and 32bit userspace etc.
49 [TCA_CANPRIO_RULES] = { /*.len = (sizeof(struct canprio_rule)*32)*/ }, /* FIXME */
50 [TCA_CANPRIO_INV_EN] = { .type = NLA_U32 },
53 struct canprio_eff_item {
54 struct hlist_node list;
59 static DEFINE_SPINLOCK(canprio_match_eff_lock);
63 struct list_head flist;
66 struct canprio_filter {
68 // For each SFF Can ID (11 bit) there is one record in this bitfield
69 DECLARE_BITMAP(match_sff, CAN_SFF_MASK + 1);
70 int inv_match_en; // Inverted match flag
71 struct hlist_head match_eff; // List of EFF frames to match
72 struct tcf_result res;
73 struct list_head link;
77 * ----------------------------------------------------------------------------
80 static void sff_match_add(struct canprio_filter *f, u32 canid, u32 mask)
84 printk("%s() invoked\n", __FUNCTION__);
88 if (mask == CAN_SFF_MASK) {
89 set_bit(canid, f->match_sff);
93 for (i = 0; i <= CAN_SFF_MASK; i++) {
94 if ((i & mask) == canid)
95 set_bit(i, f->match_sff);
99 static int eff_match_add(struct canprio_filter *f, u32 canid, u32 mask)
101 struct canprio_eff_item *eff;
104 printk("%s() invoked\n", __FUNCTION__);
105 mask &= CAN_EFF_MASK;
106 canid = canid & mask;
108 eff = kmalloc(sizeof(struct canprio_eff_item), GFP_KERNEL);
112 spin_lock(&canprio_match_eff_lock);
117 hlist_add_head_rcu(&eff->list, &f->match_eff);
119 spin_unlock(&canprio_match_eff_lock);
125 * Extracts Can ID ot ouf the sk_buff structure.
127 static u32 canprio_get_id(struct sk_buff *skb)
129 /* Can ID is inside of data field */
130 struct can_frame *cf = (struct can_frame *)skb->data;
131 //canid_t canid = cf->canid;
133 return (u32)cf->can_id;
137 * Performs the classification. Iterates over all instances of filter
138 * checking for Can ID match.
140 * @skb: Socket buffer
142 * @res: Is used for setting Class ID as a result of classification
144 * Returns value relevant for policing. Used return values:
145 * TC_POLICE_OK if succesfully classified (without regard to policing rules)
146 * TC_POLICE_UNSPEC if no matching filter was found
148 static int canprio_classify(struct sk_buff *skb, struct tcf_proto *tp,
149 struct tcf_result *res)
151 struct canprio_head *head = (struct canprio_head *)tp->root;
152 struct canprio_filter *f;
155 printk(" canprio_classify() invoked\n");
156 canid = canprio_get_id(skb);
158 list_for_each_entry(f, &head->flist, link) {
160 printk(" canprio_classify() can ID of received frame = 0x%x\n", canid);
162 if (canid & CAN_EFF_FLAG) {
163 struct canprio_eff_item *effi;
164 struct hlist_node *next;
168 hlist_for_each_entry_rcu(effi, next, &f->match_eff, list) {
169 if ((effi->canid ^ canid) & effi->mask) {
177 match = test_bit(canid, f->match_sff);
186 printk( " canprio_classify() match ok: ID 0x%x\n", canid);
190 return TC_POLICE_UNSPEC;
196 static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f,
197 unsigned long base, struct nlattr **tb,
201 printk(" canprio_set_parms invoked\n");
203 if (tb[TCA_CANPRIO_CLASSID]) {
204 f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
205 bitmap_zero(f->match_sff, CAN_SFF_MASK + 1);
206 INIT_HLIST_HEAD(&f->match_eff);
208 tcf_bind_filter(tp, &f->res, base);
215 * Looks up a filter element by its handle and returns the internal
216 * filter ID (i.e. pointer)
218 static unsigned long canprio_get(struct tcf_proto *tp, u32 handle)
220 struct canprio_head *head = (struct canprio_head *)tp->root;
221 struct canprio_filter *f;
223 //printk("canprio_get(%d) invoked\n", handle);
227 //printk("[running for_each_entry]\n");
228 list_for_each_entry(f, &head->flist, link) {
229 //printk("[f->handle = %d]\n", f->handle);
230 if (f->handle == handle) {
231 //printk("found something\n");
232 return (unsigned long) f;
240 * Is invoked when a filter element previously referenced
241 * with get() is no longer used
243 static void canprio_put(struct tcf_proto *tp, unsigned long f)
248 /* FIXME all functions with prefixes? */
249 static unsigned int gen_handle(struct tcf_proto *tp)
251 struct canprio_head *head = (struct canprio_head *)tp->root;
258 if ((head->hgenerator += 0x10000) == 0)
259 head->hgenerator = 0x10000;
261 h = head->hgenerator;
262 //if (canprio_get(tp, h) == 0)
264 tmp = canprio_get(tp, h);
265 //printk("___tried %d result %lu\n", h, tmp);
274 * Called for changing properties of an existing filter or after addition
275 * of a new filter to a class (by calling bind_tcf which binds an instance
276 * of a filter to the class).
278 * @tp: Structure representing instance of a filter.
279 * Part of a linked list of all filters.
282 * @tca: Messages passed through the Netlink from userspace.
285 static int canprio_change(struct tcf_proto *tp, unsigned long base, u32 handle,
286 struct nlattr **tca, unsigned long *arg)
289 struct canprio_head *head = (struct canprio_head *)tp->root;
290 struct canprio_filter *f = (struct canprio_filter *)*arg;
291 struct nlattr *tb[TCA_CANPRIO_MAX + 1];
294 printk(" canprio_change invoked\n");
296 if (tca[TCA_OPTIONS] == NULL)
299 //Parses a stream of attributes and stores a pointer to each attribute in
300 //the tb array accessible via the attribute type. Policy may be set to NULL
301 //if no validation is required.
302 err = nla_parse_nested(tb, TCA_CANPRIO_MAX, tca[TCA_OPTIONS], canprio_policy);
306 //Change existing filter (?)
308 if (handle && f->handle != handle)
310 return canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
313 //Create new filter (?)
315 f = kzalloc(sizeof(*f), GFP_KERNEL);
327 unsigned int i = 0x80000000;
329 if (++head->hgenerator == 0x7FFFFFFF)
330 head->hgenerator = 1;
331 } while (--i > 0 && canprio_get(tp, head->hgenerator));
334 pr_err("Insufficient number of handles\n");
338 handle = gen_handle(tp);
339 //printk("__new handle %d\n", handle);
341 //FIXME where is hgenerator initialized
345 //Configure newly created filter
346 err = canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
352 if (tb[TCA_CANPRIO_RULES] == NULL)
355 canprio_rules = nla_data(tb[TCA_CANPRIO_RULES]);
356 canprio_rules_count = (nla_len(tb[TCA_CANPRIO_RULES]) / sizeof(struct canprio_rule));
357 printk(" rules_count = %u\n", canprio_rules_count);
359 for (i = 0; i < canprio_rules_count; i++) {
360 /* FIXME: shouldn't use here the same logic as in
361 * can_rcv_filter() to filter for various combination
362 * of flags (EFF, RTR) */
363 if (canprio_rules[i].canid & CAN_EFF_FLAG) {
364 err = eff_match_add(f, canprio_rules[i].canid, canprio_rules[i].canid_mask);
368 sff_match_add(f, canprio_rules[i].canid, canprio_rules[i].canid_mask);
371 printk(" can ID to match = 0x%x with mask 0x%x\n",
372 canprio_rules[i].canid, canprio_rules[i].canid_mask);
376 if (tb[TCA_CANPRIO_INV_EN] != NULL)
377 f->inv_match_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]);
379 //Add newly created filter to list of all filters
381 list_add(&f->link, &head->flist);
383 *arg = (unsigned long) f;
388 if (*arg == 0UL && f) //FIXME why 0UL?
395 static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f)
397 struct canprio_eff_item *effi;
398 struct hlist_node *p, *n;
402 tcf_unbind_filter(tp, &f->res);
403 hlist_for_each_entry_safe(effi, p, n, &f->match_eff, list) {
411 * Remove whole filter.
413 static void canprio_destroy(struct tcf_proto *tp)
415 struct canprio_head *head = tp->root;
416 struct canprio_filter *f, *n;
418 list_for_each_entry_safe(f, n, &head->flist, link) {
420 canprio_delete_filter(tp, f);
426 * Delete one instance of a filter.
428 static int canprio_delete(struct tcf_proto *tp, unsigned long arg)
430 struct canprio_head *head = (struct canprio_head *)tp->root;
431 struct canprio_filter *t;
432 struct canprio_filter *f = (struct canprio_filter *)arg;
434 rcu_barrier(); /* Wait for completion of call_rcu()'s */
436 list_for_each_entry(t, &head->flist, link)
441 canprio_delete_filter(tp, t);
448 //FIXME copied from cls_basic, not sure if ok;
449 static int canprio_init(struct tcf_proto *tp)
451 struct canprio_head *head;
452 //printk("tp = %p\n", tp);
453 printk(" canprio_init invoked\n");
455 head = kzalloc(sizeof(*head), GFP_KERNEL);
458 INIT_LIST_HEAD(&head->flist);
460 tp->protocol = htons(ETH_P_CAN); /* Work only on AF_CAN packets - not tested! */
466 static void canprio_walk(struct tcf_proto *tp, struct tcf_walker *arg)
468 struct canprio_head *head = (struct canprio_head *) tp->root;
469 struct canprio_filter *f;
471 printk("%s() invoked\n", __FUNCTION__);
473 list_for_each_entry(f, &head->flist, link) {
474 if (arg->count < arg->skip)
477 printk("calling canprio_dump()\n");
478 if (arg->fn(tp, (unsigned long) f, arg) < 0) {
487 static int canprio_dump(struct tcf_proto *tp, unsigned long fh,
488 struct sk_buff *skb, struct tcmsg *t)
490 struct canprio_filter *f = (struct canprio_filter *) fh;
493 printk("%s() invoked\n", __FUNCTION__);
498 t->tcm_handle = f->handle;
500 nest = nla_nest_start(skb, TCA_OPTIONS);
502 goto nla_put_failure;
505 NLA_PUT_U32(skb, TCA_CANPRIO_CLASSID, f->res.classid);
508 //NLA_PUT(skb, TCA_CANPRIO_RULES, canprio_rules_count * sizeof(struct canprio_rule),
514 nla_nest_end(skb, nest);
519 nla_nest_cancel(skb, nest);
524 static struct tcf_proto_ops cls_canprio_ops __read_mostly = {
526 .classify = canprio_classify,
527 .init = canprio_init,
528 .destroy = canprio_destroy,
531 .change = canprio_change,
532 .delete = canprio_delete,
533 .walk = canprio_walk,
534 .dump = canprio_dump,
535 .owner = THIS_MODULE,
538 static int __init init_canprio(void)
540 printk("Canprio loaded\n");
541 return register_tcf_proto_ops(&cls_canprio_ops);
544 static void __exit exit_canprio(void)
546 printk("Canprio removed\n");
547 unregister_tcf_proto_ops(&cls_canprio_ops);
550 module_init(init_canprio);
551 module_exit(exit_canprio);
552 MODULE_LICENSE("GPL");
553 MODULE_AUTHOR(""); // FIXME
554 MODULE_DESCRIPTION("");