#include <linux/rcupdate.h>
#include <linux/can.h>
-#ifndef CAN_SFF_ID_BITS
- #define CAN_SFF_ID_BITS 11
- #define CAN_EFF_ID_BITS 29
-#endif
-
-#define SFF_BITMAP 1 /* Use bitmap for storing rules
- for SFF frames? */
-
/* Definition of Netlink message parts */
enum {
TCA_CANFLTR_UNSPEC,
message; Used for sending information
to userspace (when 'tc filter show' is
invoked) AND when matching EFF frames*/
-#ifdef SFF_BITMAP
DECLARE_BITMAP(match_sff, (1 << CAN_SFF_ID_BITS)); /* For each SFF CAN
ID (11 bit) there is one record in this
bitfield */
-#endif
int rules_count;
int eff_rules_count;
int sff_rules_count;
static void canfltr_sff_match_add(struct canfltr_rules *rls,
u32 can_id, u32 can_mask)
{
-#ifdef SFF_BITMAP
int i;
/* Limit can_mask and can_id to SFF range to
if ((i & can_mask) == can_id)
set_bit(i, rls->match_sff);
}
-#endif
}
/**
break;
}
}
- } else {
+ } else { /* SFF */
can_id &= CAN_SFF_MASK;
-#ifdef SFF_BITMAP
match = test_bit(can_id, r->match_sff);
-#else
- for (i = r->eff_rules_count;
- i < r->eff_rules_count + r->sff_rules_count; i++) {
- if (!(((r->rules_raw[i].can_id ^ can_id) &
- r->rules_raw[i].can_mask) & CAN_SFF_MASK)) {
- match = true;
- break;
- }
- }
-#endif
}
if (match) {
{
}
+/**
+ * canfltr_gen_handle() - Generate handle for newly created filter
+ *
+ * This code is heavily inspired by handle generator in cls_basic.c
+ */
static unsigned int canfltr_gen_handle(struct tcf_proto *tp)
{
struct canfltr_head *head = (struct canfltr_head *)tp->root;
- int i = 0xFFFF;
+ unsigned int i = 0x80000000;
- while (i-- > 0) {
- u32 h;
+ do {
+ if (++head->hgenerator == 0x7FFFFFFF)
+ head->hgenerator = 1;
+ } while (--i > 0 && canfltr_get(tp, head->hgenerator));
- head->hgenerator += 0x10000;
- if (head->hgenerator == 0)
- head->hgenerator = 0x10000;
+ if (i == 0)
+ return 0;
- h = head->hgenerator;
- if (canfltr_get(tp, h) == 0)
- return h;
- }
- return 0;
+ return head->hgenerator;
}
static void canfltr_rules_free_rcu(struct rcu_head *rcu)
int i;
rules_tmp = kzalloc(sizeof(*rules_tmp), GFP_KERNEL);
- if (rules_tmp == NULL)
+ if (!rules_tmp)
return -ENOBUFS;
err = -EINVAL;
f->handle = handle;
else {
f->handle = canfltr_gen_handle(tp);
+ if (f->handle == 0)
+ goto errout;
}
/* Configure filter */
{
struct canfltr_head *head;
- if ((tp->protocol != htons(ETH_P_ALL)) && (tp->protocol != htons(ETH_P_CAN)))
+ if ((tp->protocol != htons(ETH_P_ALL)) &&
+ (tp->protocol != htons(ETH_P_CAN)))
return -1;
/* Work only on CAN frames */
if (nest == NULL)
goto nla_put_failure;
- if (f->res.classid)
- NLA_PUT_U32(skb, TCA_CANFLTR_CLASSID, f->res.classid);
-
- NLA_PUT(skb, TCA_CANFLTR_RULES, r->rules_count *
- sizeof(struct can_filter), r->rules_raw);
+ if (f->res.classid &&
+ nla_put_u32(skb, TCA_CANFLTR_CLASSID, f->res.classid))
+ goto nla_put_failure;
+ if (nla_put(skb, TCA_CANFLTR_RULES, r->rules_count *
+ sizeof(struct can_filter), r->rules_raw))
+ goto nla_put_failure;
nla_nest_end(skb, nest);
static int __init init_canfltr(void)
{
pr_debug("canfltr: CAN filter loaded\n");
-#ifdef SFF_BITMAP
- pr_debug("canfltr: SFF rules stored in bitmap\n");
-#else
- pr_debug("canfltr: SFF rules stored in array\n");
-#endif
return register_tcf_proto_ops(&cls_canfltr_ops);
}