1 /* cls_canprio.c -- Canprio classifier.
2 * Makes decisions accoring to Can IDs.
4 * Implementation notes;
5 * parameter of functions named "base" is pointer to some parent element
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/string.h>
14 #include <linux/errno.h>
15 #include <linux/rtnetlink.h>
16 #include <linux/skbuff.h>
17 #include <net/netlink.h>
18 #include <net/act_api.h>
19 #include <net/pkt_cls.h>
20 #include <linux/can.h>
23 /* Definition of Netlink messages */
28 TCA_CANPRIO_MATCH_MASK,
31 #define TCA_CANPRIO_MAX (__TCA_CANPRIO_MAX - 1)
33 static const struct nla_policy canprio_policy[TCA_CANPRIO_MAX + 1] = {
34 [TCA_CANPRIO_CLASSID] = { .type = NLA_U32 },
35 [TCA_CANPRIO_MATCH] = { .type = NLA_U32 }, //{ .type = NLA_NESTED },
36 [TCA_CANPRIO_MATCH_MASK] = { .type = NLA_U32 },
41 struct list_head flist;
44 struct canprio_filter {
48 struct tcf_result res;
49 struct list_head link;
53 * ----------------------------------------------------------------------------
57 * Extracts Can ID ot ouf the sk_buff structure.
59 static u32 canprio_get_id(struct sk_buff *skb)
61 /* Can ID is inside of data field */
62 struct can_frame *cf = (struct can_frame *)skb->data;
63 //canid_t can_id = cf->can_id;
65 return (u32)cf->can_id;
69 * Performs the classification. Iterates over all instances of filter
70 * checking for Can ID match.
74 * @res: Is used for setting Class ID as a result of classification
76 * Returns value relevant for policing. Used return values:
77 * TC_POLICE_OK if succesfully classified (without regard to policing rules)
78 * TC_POLICE_UNSPEC if no matching filter was found
80 static int canprio_classify(struct sk_buff *skb, struct tcf_proto *tp,
81 struct tcf_result *res)
83 struct canprio_head *head = (struct canprio_head *)tp->root;
84 struct canprio_filter *f;
86 printk(" canprio_classify() invoked\n");
88 list_for_each_entry(f, &head->flist, link) {
89 printk(" canprio_classify() can ID of received frame = 0x%x\n", canprio_get_id(skb));
90 if ((canprio_get_id(skb) & f->canid_mask) == (f->canid & f->canid_mask)) {
91 printk( " canprio_classify() match ok: ID 0x%x mask 0x%x\n",
92 f->canid, f->canid_mask);
98 return TC_POLICE_UNSPEC;
104 static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f,
105 unsigned long base, struct nlattr **tb,
109 printk(" canprio_set_parms invoked\n");
111 if (tb[TCA_CANPRIO_CLASSID]) {
112 f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
113 tcf_bind_filter(tp, &f->res, base);
120 * Looks up a filter element by its handle and returns the internal filter ID
122 static unsigned long canprio_get(struct tcf_proto *tp, u32 handle)
124 unsigned long l = 0UL;
125 struct canprio_head *head = (struct canprio_head *) tp->root;
126 struct canprio_filter *f;
131 list_for_each_entry(f, &head->flist, link)
132 if (f->handle == handle)
133 l = (unsigned long) f;
139 * Is invoked when a filter element previously referenced
140 * with get() is no longer used
142 static void canprio_put(struct tcf_proto *tp, unsigned long f)
148 * Called for changing properties of an existing filter or after addition
149 * of a new filter to a class (by calling bind_tcf which binds an instance
150 * of a filter to the class).
152 * @tp: Structure representing instance of a filter.
153 * Part of a linked list of all filters.
156 * @tca: Messages passed through the Netlink from userspace.
159 static int canprio_change(struct tcf_proto *tp, unsigned long base, u32 handle,
160 struct nlattr **tca, unsigned long *arg)
163 struct canprio_head *head = (struct canprio_head *)tp->root;
164 struct canprio_filter *f = (struct canprio_filter *)*arg;
165 struct nlattr *tb[TCA_CANPRIO_MAX + 1];
167 printk(" canprio_change invoked\n");
169 if (tca[TCA_OPTIONS] == NULL)
172 //Parses a stream of attributes and stores a pointer to each attribute in
173 //the tb array accessible via the attribute type. Policy may be set to NULL
174 //if no validation is required.
175 err = nla_parse_nested(tb, TCA_CANPRIO_MAX, tca[TCA_OPTIONS], canprio_policy);
179 //Change existing filter (?)
181 if (handle && f->handle != handle)
183 return canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
186 //Create new filter (?)
188 f = kzalloc(sizeof(*f), GFP_KERNEL);
199 unsigned int i = 0x80000000;
201 if (++head->hgenerator == 0x7FFFFFFF)
202 head->hgenerator = 1;
203 } while (--i > 0 && canprio_get(tp, head->hgenerator));
206 pr_err("Insufficient number of handles\n");
210 f->handle = head->hgenerator;
214 //Configure newly created filter
215 err = canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
221 if (tb[TCA_CANPRIO_MATCH] == NULL)
224 //f->match = nla_data(tb[TCA_CANPRIO_MATCH]);
225 f->canid = nla_get_u32(tb[TCA_CANPRIO_MATCH]);
226 f->canid_mask = nla_get_u32(tb[TCA_CANPRIO_MATCH_MASK]);
227 printk(" can ID to match = 0x%x with mask 0x%x\n", f->canid, f->canid_mask);
229 //Add newly created filter to list of all filters
231 list_add(&f->link, &head->flist);
233 *arg = (unsigned long) f;
238 if (*arg == 0UL && f) //FIXME why 0UL?
245 static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f)
247 tcf_unbind_filter(tp, &f->res);
248 //tcf_exts_destroy(tp, &f->exts);
249 //tcf_em_tree_destroy(tp, &f->ematches);
254 * Remove whole filter.
256 static void canprio_destroy(struct tcf_proto *tp)
258 struct canprio_head *head = tp->root;
259 struct canprio_filter *f, *n;
261 list_for_each_entry_safe(f, n, &head->flist, link) {
263 canprio_delete_filter(tp, f);
269 * Delete one instance of a filter.
271 static int canprio_delete(struct tcf_proto *tp, unsigned long arg)
273 struct canprio_head *head = (struct canprio_head *)tp->root;
274 struct canprio_filter *t;
275 struct canprio_filter *f = (struct canprio_filter *)arg;
277 list_for_each_entry(t, &head->flist, link)
282 canprio_delete_filter(tp, t);
289 //FIXME copied from cls_basic, not sure if ok;
290 static int canprio_init(struct tcf_proto *tp)
292 struct canprio_head *head;
294 printk(" canprio_init invoked\n");
296 head = kzalloc(sizeof(*head), GFP_KERNEL);
299 INIT_LIST_HEAD(&head->flist);
305 static struct tcf_proto_ops cls_canprio_ops __read_mostly = {
307 .classify = canprio_classify,
308 .init = canprio_init,
309 .destroy = canprio_destroy,
312 .change = canprio_change,
313 .delete = canprio_delete,
314 .owner = THIS_MODULE,
317 static int __init init_canprio(void)
319 printk("Canprio loaded\n");
320 return register_tcf_proto_ops(&cls_canprio_ops);
323 static void __exit exit_canprio(void)
325 printk("Canprio removed\n");
326 unregister_tcf_proto_ops(&cls_canprio_ops);
329 module_init(init_canprio);
330 module_exit(exit_canprio);
331 MODULE_LICENSE("GPL");