#include <linux/rcupdate.h>
#include <linux/can.h>
-
-struct can_filter *canprio_rules;
-int canprio_rules_count = 0;
//--------------------------------------
/* Definition of Netlink messages */
static const struct nla_policy canprio_policy[TCA_CANPRIO_MAX + 1] = {
[TCA_CANPRIO_CLASSID] = { .type = NLA_U32 },
//FIXME Be aware of possible problems with 64bit kernel and 32bit userspace etc.
- [TCA_CANPRIO_RULES] = { .len = (sizeof(struct can_filter)) }, //FIXME
+ [TCA_CANPRIO_RULES] = { /*.len = (sizeof(struct can_filter))*/ }, //FIXME
[TCA_CANPRIO_INV_EN] = { .type = NLA_U32 },
};
struct canprio_eff_item {
struct hlist_node list;
struct rcu_head rcu;
- u32 canid;
- u32 mask;
+ struct can_filter rule;
};
static DEFINE_SPINLOCK(canprio_match_eff_lock);
+struct canprio_rules {
+ struct can_filter *rules_raw; /* Raw rules copied from netlink message;
+ Used for sending information to userspace
+ (when 'tc filter show' is invoked) */
+ DECLARE_BITMAP(match_sff, CAN_SFF_MASK + 1); /* For each SFF Can ID (11 bit)
+ there is one record in this bitfield */
+ struct hlist_head match_eff; /* List of EFF frames to match */
+ int inv_match_en; /* Inverted match flag */
+ int rules_count;
+ int eff_rules_count;
+ int sff_rules_count;
+};
+
struct canprio_head {
u32 hgenerator;
struct list_head flist;
struct canprio_filter {
u32 handle;
- // For each SFF Can ID (11 bit) there is one record in this bitfield
- DECLARE_BITMAP(match_sff, CAN_SFF_MASK + 1);
- int inv_match_en; // Inverted match flag
- struct hlist_head match_eff; // List of EFF frames to match
+ struct canprio_rules rules;
struct tcf_result res;
struct list_head link;
};
canid = canid & mask;
if (mask == CAN_SFF_MASK) {
- set_bit(canid, f->match_sff);
+ set_bit(canid, f->rules.match_sff);
return;
}
for (i = 0; i <= CAN_SFF_MASK; i++) {
if ((i & mask) == canid)
- set_bit(i, f->match_sff);
+ set_bit(i, f->rules.match_sff);
}
}
spin_lock(&canprio_match_eff_lock);
- eff->canid = canid;
- eff->mask = mask;
+ eff->rule.can_id = canid;
+ eff->rule.can_mask = mask;
- hlist_add_head_rcu(&eff->list, &f->match_eff);
+ hlist_add_head_rcu(&eff->list, &f->rules.match_eff);
spin_unlock(&canprio_match_eff_lock);
rcu_read_lock();
- hlist_for_each_entry_rcu(effi, next, &f->match_eff, list) {
- if ((effi->canid ^ canid) & effi->mask) {
+ hlist_for_each_entry_rcu(effi, next, &f->rules.match_eff, list) {
+ if ((effi->rule.can_id ^ canid) & effi->rule.can_mask) {
match = true;
break;
}
rcu_read_unlock();
} else {
- match = test_bit(canid, f->match_sff);
+ match = test_bit(canid, f->rules.match_sff);
}
- if (f->inv_match_en)
+ if (f->rules.inv_match_en)
match = !match;
if (match) {
if (tb[TCA_CANPRIO_CLASSID]) {
f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
- bitmap_zero(f->match_sff, CAN_SFF_MASK + 1);
- INIT_HLIST_HEAD(&f->match_eff);
+ bitmap_zero(f->rules.match_sff, CAN_SFF_MASK + 1);
+ INIT_HLIST_HEAD(&f->rules.match_eff);
tcf_bind_filter(tp, &f->res, base);
}
struct canprio_head *head = (struct canprio_head *)tp->root;
struct canprio_filter *f = (struct canprio_filter *)*arg;
struct nlattr *tb[TCA_CANPRIO_MAX + 1];
+ struct can_filter *canprio_nl_rules;
int i;
printk(" canprio_change invoked\n");
if (f == NULL)
goto errout;
-
err = -EINVAL;
if (handle)
f->handle = handle;
if (tb[TCA_CANPRIO_RULES] == NULL)
return -EINVAL;
- canprio_rules = nla_data(tb[TCA_CANPRIO_RULES]);
- canprio_rules_count = (nla_len(tb[TCA_CANPRIO_RULES]) / sizeof(struct can_filter));
- printk(" rules_count = %u\n", canprio_rules_count);
+ canprio_nl_rules = nla_data(tb[TCA_CANPRIO_RULES]);
+ f->rules.rules_count = (nla_len(tb[TCA_CANPRIO_RULES]) / sizeof(struct can_filter));
+ printk(" rules_count = %u\n", f->rules.rules_count);
- for (i = 0; i < canprio_rules_count; i++) {
+ err = -ENOMEM;//FIXME ENOBUFS?
+ f->rules.rules_raw = kzalloc(sizeof(struct can_filter) * f->rules.rules_count, GFP_KERNEL);
+ if (f->rules.rules_raw == NULL)
+ goto errout;
+
+ memcpy(f->rules.rules_raw, canprio_nl_rules,
+ sizeof(struct can_filter) * f->rules.rules_count);
+
+ for (i = 0; i < f->rules.rules_count; i++) {
/* FIXME: shouldn't use here the same logic as in
* can_rcv_filter() to filter for various combination
* of flags (EFF, RTR) */
- if (canprio_rules[i].can_id & CAN_EFF_FLAG) {
- err = canprio_eff_match_add(f, canprio_rules[i].can_id, canprio_rules[i].can_mask);
+ if (canprio_nl_rules[i].can_id & CAN_EFF_FLAG) {
+ err = canprio_eff_match_add(f, canprio_nl_rules[i].can_id,
+ canprio_nl_rules[i].can_mask);
if (err < 0)
goto errout;
} else {
- canprio_sff_match_add(f, canprio_rules[i].can_id, canprio_rules[i].can_mask);
+ canprio_sff_match_add(f, canprio_nl_rules[i].can_id,
+ canprio_nl_rules[i].can_mask);
}
printk(" can ID to match = 0x%x with mask 0x%x\n",
- canprio_rules[i].can_id, canprio_rules[i].can_mask);
+ canprio_nl_rules[i].can_id, canprio_nl_rules[i].can_mask);
}
- f->inv_match_en = 0;
+ f->rules.inv_match_en = 0;
if (tb[TCA_CANPRIO_INV_EN] != NULL)
- f->inv_match_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]);
+ f->rules.inv_match_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]);
//Add newly created filter to list of all filters
tcf_tree_lock(tp);
return 0;
errout:
+ if (f->rules.rules_raw != NULL) //FIXME is ok?
+ kfree(f->rules.rules_raw);
+
if (*arg == 0UL && f)
kfree(f);
rcu_barrier();
tcf_unbind_filter(tp, &f->res);
- hlist_for_each_entry_safe(effi, p, n, &f->match_eff, list) {
+ hlist_for_each_entry_safe(effi, p, n, &(f->rules.match_eff), list) {
kfree(effi);
}
+ kfree(f->rules.rules_raw);
kfree(f);
}
NLA_PUT_U32(skb, TCA_CANPRIO_CLASSID, f->res.classid);
- //NLA_PUT(skb, TCA_CANPRIO_RULES, canprio_rules_count * sizeof(struct canprio_rule),
- // canprio_rules);
+ NLA_PUT(skb, TCA_CANPRIO_RULES, f->rules.rules_count *
+ sizeof(struct can_filter), f->rules.rules_raw);
+ printk(" sending %d rules.", f->rules.rules_count);
- /* ...
- ... */
nla_nest_end(skb, nest);