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 */
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_XY] = { .type = NLA_U32 },
41 struct list_head flist;
44 struct canprio_filter {
46 u32 match; // Matching CAN ID. Will be sth like list os lists
47 struct tcf_result res;
48 struct list_head link;
52 * ----------------------------------------------------------------------------
56 * Extracts Can ID ot ouf the sk_buff structure.
58 static u32 canprio_get_id(struct sk_buff *skb)
60 /* Can ID is inside of data field */
61 struct can_frame *cf = (struct can_frame *)skb->data;
62 //canid_t can_id = cf->can_id;
64 return (u32)cf->can_id;
68 * Performs the classification. Iterates over all instances of filter
69 * checking for Can ID match.
73 * @res: Is used for setting Class ID as a result of classification
75 * Returns value relevant for policing. Used return values:
76 * TC_POLICE_OK if succesfully classified (without regard to policing rules)
77 * TC_POLICE_UNSPEC if no matching filter was found
79 static int canprio_classify(struct sk_buff *skb, struct tcf_proto *tp,
80 struct tcf_result *res)
82 struct canprio_head *head = (struct canprio_head *)tp->root;
83 struct canprio_filter *f;
85 printk(" canprio_classify invoked\n");
87 list_for_each_entry(f, &head->flist, link) {
88 if (canprio_get_id(skb) == 123) { // Should match value given by user
94 return TC_POLICE_UNSPEC;
100 static int canprio_set_parms(struct tcf_proto *tp, struct canprio_filter *f,
101 unsigned long base, struct nlattr **tb,
106 if (tb[TCA_CANPRIO_CLASSID]) {
107 f->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
108 tcf_bind_filter(tp, &f->res, base);
115 * Looks up a filter element by its handle and returns the internal filter ID
117 static unsigned long canprio_get(struct tcf_proto *tp, u32 handle)
119 unsigned long l = 0UL;
120 struct canprio_head *head = (struct canprio_head *) tp->root;
121 struct canprio_filter *f;
126 list_for_each_entry(f, &head->flist, link)
127 if (f->handle == handle)
128 l = (unsigned long) f;
134 * Is invoked when a filter element previously referenced
135 * with get() is no longer used
137 static void canprio_put(struct tcf_proto *tp, unsigned long f)
143 * Called for changing properties of an existing filter or after addition
144 * of a new filter to a class (by calling bind_tcf which binds an instance
145 * of a filter to the class).
147 * @tp: Structure representing instance of a filter.
148 * Part of a linked list of all filters.
151 * @tca: Messages passed through the Netlink from userspace.
154 static int canprio_change(struct tcf_proto *tp, unsigned long base, u32 handle,
155 struct nlattr **tca, unsigned long *arg)
158 struct canprio_head *head = (struct canprio_head *)tp->root;
159 struct canprio_filter *f = (struct canprio_filter *)*arg;
160 struct nlattr *tb[TCA_CANPRIO_MAX + 1];
162 printk(" canprio_change invoked\n");
164 if (tca[TCA_OPTIONS] == NULL)
167 err = nla_parse_nested(tb, TCA_CANPRIO_MAX, tca[TCA_OPTIONS], canprio_policy);
171 //Change existing filter (?)
173 if (handle && f->handle != handle)
175 return canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
178 //Create new filter (?)
180 f = kzalloc(sizeof(*f), GFP_KERNEL);
191 unsigned int i = 0x80000000;
193 if (++head->hgenerator == 0x7FFFFFFF)
194 head->hgenerator = 1;
195 } while (--i > 0 && canprio_get(tp, head->hgenerator));
198 pr_err("Insufficient number of handles\n");
202 f->handle = head->hgenerator;
206 //Configure newly created filter
207 err = canprio_set_parms(tp, f, base, tb, tca[TCA_RATE]);
213 if (tb[TCA_CANPRIO_MATCH] == NULL)
216 //f->match = nla_data(tb[TCA_CANPRIO_MATCH]);
217 f->match = nla_get_u32(tb[TCA_CANPRIO_MATCH]);
218 printk(" match = %d\n", f->match);
220 //Add newly created filter to list of all filters
222 list_add(&f->link, &head->flist);
224 *arg = (unsigned long) f;
229 if (*arg == 0UL && f) //FIXME why 0UL?
236 static void canprio_delete_filter(struct tcf_proto *tp, struct canprio_filter *f)
238 tcf_unbind_filter(tp, &f->res);
239 //tcf_exts_destroy(tp, &f->exts);
240 //tcf_em_tree_destroy(tp, &f->ematches);
245 * Remove whole filter.
247 static void canprio_destroy(struct tcf_proto *tp)
249 struct canprio_head *head = tp->root;
250 struct canprio_filter *f, *n;
252 list_for_each_entry_safe(f, n, &head->flist, link) {
254 canprio_delete_filter(tp, f);
260 * Delete one instance of a filter.
262 static int canprio_delete(struct tcf_proto *tp, unsigned long arg)
264 struct canprio_head *head = (struct canprio_head *)tp->root;
265 struct canprio_filter *t;
266 struct canprio_filter *f = (struct canprio_filter *)arg;
268 list_for_each_entry(t, &head->flist, link)
273 canprio_delete_filter(tp, t);
280 //FIXME copied from cls_basic, not sure if ok;
281 static int canprio_init(struct tcf_proto *tp)
283 struct canprio_head *head;
285 printk(" canprio_init invoked\n");
287 head = kzalloc(sizeof(*head), GFP_KERNEL);
290 INIT_LIST_HEAD(&head->flist);
296 static struct tcf_proto_ops cls_canprio_ops __read_mostly = {
298 .classify = canprio_classify,
299 .init = canprio_init,
300 .destroy = canprio_destroy,
303 .change = canprio_change,
304 .delete = canprio_delete,
305 .owner = THIS_MODULE,
308 static int __init init_canprio(void)
310 printk("Canprio loaded\n");
311 return register_tcf_proto_ops(&cls_canprio_ops);
314 static void __exit exit_canprio(void)
316 printk("Canprio removed\n");
317 unregister_tcf_proto_ops(&cls_canprio_ops);
320 module_init(init_canprio);
321 module_exit(exit_canprio);
322 MODULE_LICENSE("GPL");