#include <net/pkt_cls.h>
#include <linux/can.h>
#include <linux/bitmap.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
//--------------------------------------
//FIXME put in some *.h file shared with userspace "tc"?
struct canprio_rule *canprio_rules;
int canprio_rules_count = 0;
-int canprio_inv_en = 0;
//--------------------------------------
/* Definition of Netlink messages */
[TCA_CANPRIO_INV_EN] = { .type = NLA_U32 },
};
+struct canprio_eff_item {
+ struct hlist_node list;
+ struct rcu_head rcu;
+ u32 canid;
+ u32 mask;
+};
+static DEFINE_SPINLOCK(canprio_match_eff_lock);
+
struct canprio_head {
- u32 hgenerator;
- struct list_head flist;
+ u32 hgenerator;
+ struct list_head flist;
};
struct canprio_filter {
- u32 handle;
+ u32 handle;
// For each SFF Can ID (11 bit) there is one record in this bitfield
- DECLARE_BITMAP(match, CAN_SFF_MASK + 1);
- struct tcf_result res;
- struct list_head link;
+ DECLARE_BITMAP(match_sff, CAN_SFF_MASK + 1);
+ int inv_match_en;
+ struct hlist_head match_eff;
+ struct tcf_result res;
+ struct list_head link;
};
/*
static void sff_match_add(struct canprio_filter *f, u32 canid, u32 mask)
{
int i;
+
+ mask &= CAN_SFF_MASK;
canid = canid & mask;
- if (mask >= CAN_SFF_MASK) {
- set_bit(canid, f->match);
+ if (mask == CAN_SFF_MASK) {
+ set_bit(canid, f->match_sff);
return;
}
for (i = 0; i <= CAN_SFF_MASK; i++) {
if ((i & mask) == canid)
- set_bit(i, f->match);
+ set_bit(i, f->match_sff);
}
}
-static void eff_match_add(struct canprio_filter *f, u32 canid, u32 mask)
+static int eff_match_add(struct canprio_filter *f, u32 canid, u32 mask)
{
+ struct canprio_eff_item *eff;
+ int err = 0;
+
+ mask &= CAN_EFF_MASK;
+ canid = canid & mask;
+
+ eff = kmalloc(sizeof(struct canprio_eff_item), GFP_KERNEL);
+ if (!eff)
+ return -ENOMEM;
+
+ spin_lock(&canprio_match_eff_lock);
+ eff->canid = canid;
+ eff->mask = mask;
+ hlist_add_head_rcu(&eff->list, &f->match_eff);
+
+ spin_unlock(&canprio_match_eff_lock);
+
+ return err;
}
/*
{
/* Can ID is inside of data field */
struct can_frame *cf = (struct can_frame *)skb->data;
- //canid_t can_id = cf->can_id;
+ //canid_t canid = cf->canid;
return (u32)cf->can_id;
}
u32 canid;
printk(" canprio_classify() invoked\n");
+ canid = canprio_get_id(skb);
list_for_each_entry(f, &head->flist, link) {
- canid = canprio_get_id(skb);
+ int match = 0;
printk(" canprio_classify() can ID of received frame = 0x%x\n", canid);
if (canid & CAN_EFF_FLAG) {
+ struct canprio_eff_item *effi;
+ struct hlist_node *next;
+
+ rcu_read_lock();
+
+ hlist_for_each_entry_rcu(effi, next, &f->match_eff, list) {
+ if((effi->canid ^ canid) & effi->mask) {
+ match = 1;
+ break;
+ }
+ }
+ rcu_read_unlock();
} else {
- if(test_bit(canid, f->match) ^ canprio_inv_en) {
- printk( " canprio_classify() match ok: ID 0x%x\n", canid);
- *res = f->res;
- return TC_POLICE_OK;
+ if(test_bit(canid, f->match_sff)) {
+ match = 1;
}
}
+
+ if (f->inv_match_en)
+ match = !match;
+
+ if (match) {
+ *res = f->res;
+ return TC_POLICE_OK;
+ printk( " canprio_classify() match ok: ID 0x%x\n", canid);
+ }
}
return TC_POLICE_UNSPEC;
if (tb[TCA_CANPRIO_CLASSID]) {
f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
- bitmap_zero(f->match, CAN_SFF_MASK + 1);
+ bitmap_zero(f->match_sff, CAN_SFF_MASK + 1);
+ INIT_HLIST_HEAD(&f->match_eff);
tcf_bind_filter(tp, &f->res, base);
}
for (i = 0; i < canprio_rules_count; i++) {
if (canprio_rules[i].canid & CAN_EFF_FLAG) {
- eff_match_add(f, canprio_rules[i].canid, canprio_rules[i].canid_mask);
+ err = eff_match_add(f, canprio_rules[i].canid, canprio_rules[i].canid_mask);
+ if (err < 0)
+ goto errout;
} else {
sff_match_add(f, canprio_rules[i].canid, canprio_rules[i].canid_mask);
}
canprio_rules[i].canid, canprio_rules[i].canid_mask);
}
- canprio_inv_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]);
+ f->inv_match_en = 0;
+ if (tb[TCA_CANPRIO_INV_EN] != NULL)
+ f->inv_match_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]);
//Add newly created filter to list of all filters
tcf_tree_lock(tp);
static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f)
{
- tcf_unbind_filter(tp, &f->res);
- //tcf_exts_destroy(tp, &f->exts);
- //tcf_em_tree_destroy(tp, &f->ematches);
+ struct canprio_eff_item *effi;
+ struct hlist_node *p, *n;
+
+ rcu_barrier();
+
+ tcf_unbind_filter(tp, &f->res);
+ hlist_for_each_entry_safe(effi, p, n, &f->match_eff, list) {
+ kfree(effi);
+ }
+
kfree(f);
}
struct canprio_filter *t;
struct canprio_filter *f = (struct canprio_filter *)arg;
+ rcu_barrier(); /* Wait for completion of call_rcu()'s */
+
list_for_each_entry(t, &head->flist, link)
if (t == f) {
tcf_tree_lock(tp);