/*
- * cls_canprio.c -- Canprio classifier.
+ * cls_can.c -- CAN classifier.
* Makes decisions accoring to controller area network (CAN) identifiers.
*
* This program is free software; you can distribute it and/or
#define SFF_BITMAP 1
-
/* Definition of Netlink messages */
enum {
- TCA_CANPRIO_A_UNSPEC,
- TCA_CANPRIO_CLASSID,
- TCA_CANPRIO_RULES, /* Array of can_filter structs; We are able
+ TCA_CANFLTR_UNSPEC,
+ TCA_CANFLTR_CLASSID,
+ TCA_CANFLTR_RULES, /* Array of can_filter structs; We are able
to determine the length after receiving */
- TCA_CANPRIO_INV_EN, /* enable inverse rules */
- __TCA_CANPRIO_MAX,
+ __TCA_CANFLTR_MAX
};
-#define TCA_CANPRIO_MAX (__TCA_CANPRIO_MAX - 1)
+#define TCA_CANFLTR_MAX (__TCA_CANFLTR_MAX - 1)
-static const struct nla_policy canprio_policy[TCA_CANPRIO_MAX + 1] = {
- [TCA_CANPRIO_CLASSID] = { .type = NLA_U32 },
+static const struct nla_policy canfltr_policy[TCA_CANFLTR_MAX + 1] = {
+ [TCA_CANFLTR_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_INV_EN] = { .type = NLA_U32 },
+ [TCA_CANFLTR_RULES] = { /*.len = (sizeof(struct can_filter))*/ } //FIXME
};
-struct canprio_rules {
+struct canfltr_rules {
struct can_filter *rules_raw; /* Raw rules copied from netlink message;
Used for sending information to userspace
(when 'tc filter show' is invoked) AND
struct rcu_head rcu;
};
-struct canprio_head {
+struct canfltr_head {
u32 hgenerator;
struct list_head flist;
};
-struct canprio_filter {
+struct canfltr_state {
u32 handle;
- struct canprio_rules *rules; /* All rules necessary for classification */
+ struct canfltr_rules *rules; /* All rules necessary for classification */
struct tcf_result res; /* Class ID (flow id) the instance
of a filter is bound to */
struct list_head link;
*/
#ifdef SFF_BITMAP
-static void canprio_sff_match_add(struct canprio_rules *rls, u32 can_id, u32 can_mask)
+static void canfltr_sff_match_add(struct canfltr_rules *rls, u32 can_id, u32 can_mask)
{
int i;
/*
* Extracts Can ID ot ouf the sk_buff structure.
*/
-static canid_t canprio_get_id(struct sk_buff *skb)
+static canid_t canfltr_get_id(struct sk_buff *skb)
{
/* Can ID is inside of data field */
struct can_frame *cf = (struct can_frame *)skb->data;
* TC_POLICE_OK if succesfully classified (without regard to policing rules)
* TC_POLICE_UNSPEC if no matching filter was found
*/
-static int canprio_classify(struct sk_buff *skb, struct tcf_proto *tp,
+static int canfltr_classify(struct sk_buff *skb, struct tcf_proto *tp,
struct tcf_result *res)
{
- struct canprio_head *head = (struct canprio_head *)tp->root;
- struct canprio_filter *f;
- struct canprio_rules *r;
+ struct canfltr_head *head = (struct canfltr_head *)tp->root;
+ struct canfltr_state *f;
+ struct canfltr_rules *r;
u32 can_id;
int i;
- can_id = (u32)canprio_get_id(skb);
+ can_id = (u32)canfltr_get_id(skb);
rcu_read_lock();
list_for_each_entry(f, &head->flist, link) {
* Looks up a filter element by its handle and returns the internal
* filter ID (i.e. pointer)
*/
-static unsigned long canprio_get(struct tcf_proto *tp, u32 handle)
+static unsigned long canfltr_get(struct tcf_proto *tp, u32 handle)
{
- struct canprio_head *head = (struct canprio_head *)tp->root;
- struct canprio_filter *f;
+ struct canfltr_head *head = (struct canfltr_head *)tp->root;
+ struct canfltr_state *f;
if (head == NULL)
return 0UL;
* Is invoked when a filter element previously referenced
* with get() is no longer used
*/
-static void canprio_put(struct tcf_proto *tp, unsigned long f)
+static void canfltr_put(struct tcf_proto *tp, unsigned long f)
{
}
-static unsigned int canprio_gen_handle(struct tcf_proto *tp)
+static unsigned int canfltr_gen_handle(struct tcf_proto *tp)
{
- struct canprio_head *head = (struct canprio_head *)tp->root;
+ struct canfltr_head *head = (struct canfltr_head *)tp->root;
int i = 0xFFFF;
while (i-- > 0) {
head->hgenerator = 0x10000;
h = head->hgenerator;
- if (canprio_get(tp, h) == 0);
+ if (canfltr_get(tp, h) == 0);
return h;
}
return 0;
}
-static void canprio_rules_free_rcu(struct rcu_head *rcu)
+static void canfltr_rules_free_rcu(struct rcu_head *rcu)
{
- kfree(container_of(rcu, struct canprio_rules, rcu));
+ kfree(container_of(rcu, struct canfltr_rules, rcu));
}
-static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f,
+static int canfltr_set_parms(struct tcf_proto *tp, struct canfltr_state *f,
unsigned long base, struct nlattr **tb,
struct nlattr *est)
{
- struct can_filter *canprio_nl_rules;
- struct canprio_rules *rules_tmp;
+ struct can_filter *canfltr_nl_rules;
+ struct canfltr_rules *rules_tmp;
int err;
int i;
return -ENOBUFS;
err = -EINVAL;
- if (tb[TCA_CANPRIO_CLASSID] == NULL)
+ if (tb[TCA_CANFLTR_CLASSID] == NULL)
goto errout;
- if (tb[TCA_CANPRIO_RULES]) {
- canprio_nl_rules = nla_data(tb[TCA_CANPRIO_RULES]);
+ if (tb[TCA_CANFLTR_RULES]) {
+ canfltr_nl_rules = nla_data(tb[TCA_CANFLTR_RULES]);
rules_tmp->sff_rules_count = 0;
rules_tmp->eff_rules_count = 0;
rules_tmp->rules_count =
- (nla_len(tb[TCA_CANPRIO_RULES]) / sizeof(struct can_filter));
+ (nla_len(tb[TCA_CANFLTR_RULES]) / sizeof(struct can_filter));
rules_tmp->rules_raw =
kzalloc(sizeof(struct can_filter) * rules_tmp->rules_count, GFP_KERNEL);
/* Process EFF frames */
for (i = 0; i < rules_tmp->rules_count; i++) {
- if ((canprio_nl_rules[i].can_id & CAN_EFF_FLAG) &&
- (canprio_nl_rules[i].can_mask & CAN_EFF_FLAG)) {
+ if ((canfltr_nl_rules[i].can_id & CAN_EFF_FLAG) &&
+ (canfltr_nl_rules[i].can_mask & CAN_EFF_FLAG)) {
memcpy(rules_tmp->rules_raw + rules_tmp->eff_rules_count,
- &canprio_nl_rules[i], sizeof(struct can_filter));
+ &canfltr_nl_rules[i], sizeof(struct can_filter));
rules_tmp->eff_rules_count ++;
} else {
continue;
/* Process SFF frames
We need two for() loops for copying rules into two contiguous areas in rules_raw */
for (i = 0; i < rules_tmp->rules_count; i++) {
- if ((canprio_nl_rules[i].can_id & CAN_EFF_FLAG) &&
- (canprio_nl_rules[i].can_mask & CAN_EFF_FLAG)) {
+ if ((canfltr_nl_rules[i].can_id & CAN_EFF_FLAG) &&
+ (canfltr_nl_rules[i].can_mask & CAN_EFF_FLAG)) {
continue;
} else {
memcpy(rules_tmp->rules_raw + rules_tmp->eff_rules_count + rules_tmp->sff_rules_count,
- &canprio_nl_rules[i], sizeof(struct can_filter));
+ &canfltr_nl_rules[i], sizeof(struct can_filter));
rules_tmp->sff_rules_count ++;
#ifdef SFF_BITMAP
- canprio_sff_match_add(rules_tmp, canprio_nl_rules[i].can_id,
- canprio_nl_rules[i].can_mask);
+ canfltr_sff_match_add(rules_tmp, canfltr_nl_rules[i].can_id,
+ canfltr_nl_rules[i].can_mask);
#endif
}
}
}
- if (tb[TCA_CANPRIO_INV_EN] != NULL)
- rules_tmp->inv_match_en = nla_get_u32(tb[TCA_CANPRIO_INV_EN]);
-
if (f->rules == NULL) { /* Setting parameters for newly created filter */
rcu_assign_pointer(f->rules, rules_tmp);
} else { /* Changing existing filter */
- struct canprio_rules *rules_old;
+ struct canfltr_rules *rules_old;
rules_old = xchg(&f->rules, rules_tmp);
- call_rcu(&rules_old->rcu, canprio_rules_free_rcu);
+ call_rcu(&rules_old->rcu, canfltr_rules_free_rcu);
}
return 0;
* @tca: Messages passed through the Netlink from userspace.
* @arg:
*/
-static int canprio_change(struct tcf_proto *tp, unsigned long base, u32 handle,
+static int canfltr_change(struct tcf_proto *tp, unsigned long base, u32 handle,
struct nlattr **tca, unsigned long *arg)
{
- 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 canfltr_head *head = (struct canfltr_head *)tp->root;
+ struct canfltr_state *f = (struct canfltr_state *)*arg;
+ struct nlattr *tb[TCA_CANFLTR_MAX + 1];
int err;
if (tca[TCA_OPTIONS] == NULL)
/* Parses a stream of attributes and stores a pointer to each attribute in
the tb array accessible via the attribute type. Policy may be set to NULL
if no validation is required.*/
- err = nla_parse_nested(tb, TCA_CANPRIO_MAX, tca[TCA_OPTIONS], canprio_policy);
+ err = nla_parse_nested(tb, TCA_CANFLTR_MAX, tca[TCA_OPTIONS], canfltr_policy);
if (err < 0)
return err;
/* Change existing filter (remove all settings and add
if (handle && f->handle != handle)
return -EINVAL;
- return canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
+ return canfltr_set_parms(tp, f, base, tb, tca[TCA_RATE]);
}
/* Create new filter */
if (f == NULL)
goto errout;
- if (tb[TCA_CANPRIO_CLASSID]) {
+ if (tb[TCA_CANFLTR_CLASSID]) {
f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
tcf_bind_filter(tp, &f->res, base);
}
if (handle) /* handle passed from userspace */
f->handle = handle;
else {
- f->handle = canprio_gen_handle(tp);
+ f->handle = canfltr_gen_handle(tp);
}
/* Configure filter */
- err = canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
+ err = canfltr_set_parms(tp, f, base, tb, tca[TCA_RATE]);
if (err < 0)
goto errout;
}
-static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f)
+static void canfltr_delete_filter(struct tcf_proto *tp, struct canfltr_state *f)
{
tcf_unbind_filter(tp, &f->res);
/*
* Remove whole filter.
*/
-static void canprio_destroy(struct tcf_proto *tp)
+static void canfltr_destroy(struct tcf_proto *tp)
{
- struct canprio_head *head = tp->root;
- struct canprio_filter *f, *n;
+ struct canfltr_head *head = tp->root;
+ struct canfltr_state *f, *n;
list_for_each_entry_safe(f, n, &head->flist, link) {
list_del(&f->link);
- canprio_delete_filter(tp, f);
+ canfltr_delete_filter(tp, f);
}
kfree(head);
}
/*
* Delete one instance of a filter.
*/
-static int canprio_delete(struct tcf_proto *tp, unsigned long arg)
+static int canfltr_delete(struct tcf_proto *tp, unsigned long arg)
{
- struct canprio_head *head = (struct canprio_head *)tp->root;
- struct canprio_filter *t;
- struct canprio_filter *f = (struct canprio_filter *)arg;
+ struct canfltr_head *head = (struct canfltr_head *)tp->root;
+ struct canfltr_state *t;
+ struct canfltr_state *f = (struct canfltr_state *)arg;
rcu_barrier(); /* Wait for completion of call_rcu()'s */
tcf_tree_lock(tp);
list_del(&t->link);
tcf_tree_unlock(tp);
- canprio_delete_filter(tp, t);
+ canfltr_delete_filter(tp, t);
return 0;
}
/*
* Initialize filter
*/
-static int canprio_init(struct tcf_proto *tp)
+static int canfltr_init(struct tcf_proto *tp)
{
- struct canprio_head *head;
+ struct canfltr_head *head;
head = kzalloc(sizeof(*head), GFP_KERNEL);
if (head == NULL)
* Iterates over all elements of a filter and invokes a callback function
* for each of them. This is used to obtain diagnostic data
*/
-static void canprio_walk(struct tcf_proto *tp, struct tcf_walker *arg)
+static void canfltr_walk(struct tcf_proto *tp, struct tcf_walker *arg)
{
- struct canprio_head *head = (struct canprio_head *) tp->root;
- struct canprio_filter *f;
+ struct canfltr_head *head = (struct canfltr_head *) tp->root;
+ struct canfltr_state *f;
list_for_each_entry(f, &head->flist, link) {
if (arg->count < arg->skip)
/*
* Returns diagnostic data for a filter or one of its elements.
*/
-static int canprio_dump(struct tcf_proto *tp, unsigned long fh,
+static int canfltr_dump(struct tcf_proto *tp, unsigned long fh,
struct sk_buff *skb, struct tcmsg *t)
{
- struct canprio_filter *f = (struct canprio_filter *) fh;
+ struct canfltr_state *f = (struct canfltr_state *) fh;
struct nlattr *nest;
- struct canprio_rules *r;
+ struct canfltr_rules *r;
if (f == NULL)
return skb->len;
goto nla_put_failure;
if (f->res.classid)
- NLA_PUT_U32(skb, TCA_CANPRIO_CLASSID, f->res.classid);
+ NLA_PUT_U32(skb, TCA_CANFLTR_CLASSID, f->res.classid);
- NLA_PUT(skb, TCA_CANPRIO_RULES, r->rules_count *
+ NLA_PUT(skb, TCA_CANFLTR_RULES, r->rules_count *
sizeof(struct can_filter), r->rules_raw);
}
-static struct tcf_proto_ops cls_canprio_ops __read_mostly = {
- .kind = "canprio",
- .classify = canprio_classify,
- .init = canprio_init,
- .destroy = canprio_destroy,
- .get = canprio_get,
- .put = canprio_put,
- .change = canprio_change,
- .delete = canprio_delete,
- .walk = canprio_walk,
- .dump = canprio_dump,
+static struct tcf_proto_ops cls_canfltr_ops __read_mostly = {
+ .kind = "can",
+ .classify = canfltr_classify,
+ .init = canfltr_init,
+ .destroy = canfltr_destroy,
+ .get = canfltr_get,
+ .put = canfltr_put,
+ .change = canfltr_change,
+ .delete = canfltr_delete,
+ .walk = canfltr_walk,
+ .dump = canfltr_dump,
.owner = THIS_MODULE,
};
-static int __init init_canprio(void)
+static int __init init_canfltr(void)
{
- pr_debug("Canprio loaded\n");
+ pr_debug("canfltr: CAN filter loaded\n");
#ifdef SFF_BITMAP
- pr_debug("SFF frames stored in bitmap\n");
+ pr_debug("canfltr: SFF rules stored in bitmap\n");
#else
- pr_debug("SFF frames stored in array\n");
+ pr_debug("canfltr: SFF rules stored in array\n");
#endif
- return register_tcf_proto_ops(&cls_canprio_ops);
+ return register_tcf_proto_ops(&cls_canfltr_ops);
}
-static void __exit exit_canprio(void)
+static void __exit exit_canfltr(void)
{
- pr_debug("Canprio removed\n");
- unregister_tcf_proto_ops(&cls_canprio_ops);
+ pr_debug("canfltr: CAN filter removed\n");
+ unregister_tcf_proto_ops(&cls_canfltr_ops);
}
-module_init(init_canprio);
-module_exit(exit_canprio);
+module_init(init_canfltr);
+module_exit(exit_canfltr);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(""); // FIXME
MODULE_DESCRIPTION("Controller Area Network can_id classifier");