]> rtime.felk.cvut.cz Git - lisovros/linux_canprio.git/blobdiff - net/sched/cls_can.c
cls_can: Handle generator now uses full 32 bits for its values.
[lisovros/linux_canprio.git] / net / sched / cls_can.c
index d32ad0784522ef70708fc76ae98278ab26219b26..111668e41e821b687b7ced4ef63eb7df0381977e 100644 (file)
@@ -12,7 +12,7 @@
  *             (c) 2011 Volkswagen Group Research
  * Authors:    Michal Sojka <sojkam1@fel.cvut.cz>
  *             Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Rostislav Lisovy <lisovy@kormus.cz>
+ *             Rostislav Lisovy <lisovy@gmail.cz>
  * Funded by:  Volkswagen Group Research
  *
  * Some function descriptions are heavily inspired by article "Linux Network
 #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,
@@ -65,12 +57,9 @@ struct canfltr_rules {
                                        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 inv_match_en;               /* Inverted match flag */
        int rules_count;
        int eff_rules_count;
        int sff_rules_count;
@@ -99,7 +88,6 @@ struct canfltr_state {
 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
@@ -126,11 +114,10 @@ static void canfltr_sff_match_add(struct canfltr_rules *rls,
                if ((i & can_mask) == can_id)
                        set_bit(i, rls->match_sff);
        }
-#endif
 }
 
-/*
- * Extracts Can ID out of the sk_buff structure.
+/**
+ * canfltr_get_id() - Extracts Can ID out of the sk_buff structure.
  */
 static canid_t canfltr_get_id(struct sk_buff *skb)
 {
@@ -140,19 +127,20 @@ static canid_t canfltr_get_id(struct sk_buff *skb)
        return cf->can_id;
 }
 
-/*
- * Performs the classification. Iterates over all instances of filter,
- * checking for CAN ID match.
+/**
+ * canfltr_classify() - Performs the classification.
  *
  * @skb: Socket buffer
  * @tp:
  * @res: Is used for setting Class ID as a result of classification
  *
+ * Iterates over all instances of filter, checking for CAN ID match.
+ *
  * Returns value relevant for policing. Used return values:
  *   TC_POLICE_OK if succesfully classified (without regard to policing rules)
  *   TC_POLICE_UNSPEC if no matching rule was found
  */
-static int canfltr_classify(struct sk_buff *skb, struct tcf_proto *tp,
+static int canfltr_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                          struct tcf_result *res)
 {
        struct canfltr_head *head = (struct canfltr_head *)tp->root;
@@ -179,20 +167,9 @@ static int canfltr_classify(struct sk_buff *skb, struct tcf_proto *tp,
                                        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) {
@@ -206,9 +183,9 @@ static int canfltr_classify(struct sk_buff *skb, struct tcf_proto *tp,
        return TC_POLICE_UNSPEC;
 }
 
-/*
- * Looks up a filter element by its handle and returns the internal
- * filter ID (i.e. pointer)
+/**
+ * canfltr_get() - Looks up a filter element by its handle and returns the
+ * internal filter ID (i.e. pointer)
  */
 static unsigned long canfltr_get(struct tcf_proto *tp, u32 handle)
 {
@@ -226,31 +203,33 @@ static unsigned long canfltr_get(struct tcf_proto *tp, u32 handle)
        return 0UL;
 }
 
-/*
- * Is invoked when a filter element previously referenced
+/**
+ * canfltr_put() - Is invoked when a filter element previously referenced
  * with get() is no longer used
  */
 static void canfltr_put(struct tcf_proto *tp, unsigned long f)
 {
 }
 
+/**
+ * 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)
@@ -268,8 +247,8 @@ static int canfltr_set_parms(struct tcf_proto *tp, struct canfltr_state *f,
        int i;
 
        rules_tmp = kzalloc(sizeof(*rules_tmp), GFP_KERNEL);
-       if (rules_tmp == NULL)
-               return -ENOBUFS; /* XXX: Why not -ENOMEM? */
+       if (!rules_tmp)
+               return -ENOBUFS;
 
        err = -EINVAL;
        if (tb[TCA_CANFLTR_CLASSID] == NULL)
@@ -342,10 +321,10 @@ errout:
        return err;
 }
 
-/*
- * Called for changing properties of an existing filter or after addition
- * of a new filter to a class (by calling bind_tcf which binds an instance
- * of a filter to the class).
+/**
+ * canfltr_change() - Called for changing properties of an existing filter or
+ * after addition of a new filter to a class (by calling bind_tcf which binds
+ * an instance of a filter to the class).
  *
  * @tp:     Structure representing instance of a filter.
  *          Part of a linked list of all filters.
@@ -397,6 +376,8 @@ static int canfltr_change(struct tcf_proto *tp, unsigned long base, u32 handle,
                f->handle = handle;
        else {
                f->handle = canfltr_gen_handle(tp);
+               if (f->handle == 0)
+                       goto errout;
        }
 
        /* Configure filter */
@@ -431,8 +412,8 @@ static void canfltr_delete_filter(struct tcf_proto *tp,
        kfree(f);
 }
 
-/*
- * Remove whole filter.
+/**
+ * canfltr_destroy() - Remove whole filter.
  */
 static void canfltr_destroy(struct tcf_proto *tp)
 {
@@ -446,8 +427,8 @@ static void canfltr_destroy(struct tcf_proto *tp)
        kfree(head);
 }
 
-/*
- * Delete one instance of a filter.
+/**
+ * canfltr_delete() - Delete one instance of a filter.
  */
 static int canfltr_delete(struct tcf_proto *tp, unsigned long arg)
 {
@@ -470,27 +451,34 @@ static int canfltr_delete(struct tcf_proto *tp, unsigned long arg)
 }
 
 
-/*
- * Initialize filter
+/**
+ * canfltr_init() - Initialize filter
  */
 static int canfltr_init(struct tcf_proto *tp)
 {
        struct canfltr_head *head;
 
+       if ((tp->protocol != htons(ETH_P_ALL)) &&
+           (tp->protocol != htons(ETH_P_CAN)))
+               return -1;
+
+       /* Work only on CAN frames */
+       if (tp->protocol == htons(ETH_P_ALL))
+               tp->protocol = htons(ETH_P_CAN);
+
        head = kzalloc(sizeof(*head), GFP_KERNEL);
        if (head == NULL)
                return -ENOBUFS;
 
        INIT_LIST_HEAD(&head->flist);
        tp->root = head;
-       tp->protocol = htons(ETH_P_CAN); /* Work only on AF_CAN packets - not tested! */
 
        return 0;
 }
 
-/*
- * Iterates over all elements of a filter and invokes a callback function
- * for each of them. This is used to obtain diagnostic data
+/**
+ * canfltr_walk() - 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 canfltr_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 {
@@ -510,8 +498,8 @@ skip:
        }
 }
 
-/*
- * Returns diagnostic data for a filter or one of its elements.
+/**
+ * canfltr_dump() - Returns diagnostic data for a filter or one of its elements.
  */
 static int canfltr_dump(struct tcf_proto *tp, unsigned long fh,
                        struct sk_buff *skb, struct tcmsg *t)
@@ -567,11 +555,6 @@ static struct tcf_proto_ops cls_canfltr_ops __read_mostly = {
 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);
 }
 
@@ -584,5 +567,5 @@ static void __exit exit_canfltr(void)
 module_init(init_canfltr);
 module_exit(exit_canfltr);
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Rostislav Lisovy <lisovy@kormus.cz>");
+MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.cz>");
 MODULE_DESCRIPTION("Controller Area Network classifier");