2 * f_canprio.c Filter for CAN packets
4 * This program is free software; you can distribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Idea: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
10 * Copyright: (c) 2011 Czech Technical University in Prague
11 * (c) 2011 Volkswagen Group Research
12 * Authors: Michal Sojka <sojkam1@fel.cvut.cz>
13 * Pavel Pisa <pisa@cmp.felk.cvut.cz>
14 * Rostislav Lisovy <lisovy@kormus.cz>
15 * Founded by: Volkswagen Group Research
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
33 #ifdef CONFIG_HAVE_LINUX_CAN_H
34 #include "linux/can.h"
36 #elif !defined(CAN_EFF_FLAG)
37 /* special address description flags for the CAN_ID */
38 #define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
39 #define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
40 #define CAN_ERR_FLAG 0x20000000U /* error frame */
42 /* valid bits in CAN ID for frame formats */
43 #define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
44 #define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
45 #define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
47 typedef __u32 canid_t;
56 static void explain(void)
58 fprintf(stderr, "Usage: ... canprio [ MATCHSPEC ] [ flowid FLOWID ]\n"
60 "Where: MATCHSPEC := { matchid FILTERID | matcheid FILTERID | \n"
62 " FILTERID := CANID:MASK \n"
64 "NOTE: CLASSID, CANID, MASK is parsed as hexadecimal input.\n");
67 static int canprio_parse_opt(struct filter_util *qu, char *handle,
68 int argc, char **argv, struct nlmsghdr *n)
70 struct tcmsg *t = NLMSG_DATA(n); // Why?
72 struct can_filter canprio_rules[32];
82 h = strtol(handle, NULL, 0);
83 if (h == LONG_MIN || h == LONG_MAX) {
84 fprintf(stderr, "Illegal handle \"%s\", must be numeric.\n",
90 t->tcm_handle = h; // Why?
92 tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len));
93 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
96 //---------------------- legacy option; will be deleted in future -------------
97 if (matches(*argv, "match") == 0) {
100 if (sscanf(*argv, "%"SCNx32 ":" "%"SCNx32, &can_id, &can_mask) != 2) {
101 fprintf(stderr, "improperly formed Can ID & mask '%s'\n", *argv);
105 //printf("... 0x%x:0x%x]\n", can_id, can_mask);
106 if (can_id >= 0) {// FIXME boundary check
107 canprio_rules[rules_count].can_id = can_id;
108 canprio_rules[rules_count].can_mask = can_mask;
111 //---------------------- legacy option; will be deleted in future -------------
113 } else if (matches(*argv, "matchid") == 0) { //Parse SFF ID
116 if (sscanf(*argv, "%"SCNx32 ":" "%"SCNx32, &can_id, &can_mask) != 2) {
117 fprintf(stderr, "improperly formed Can ID & mask '%s'\n", *argv);
121 if (can_id & ~CAN_SFF_MASK) { //FIXME what about RTR flags?
122 fprintf(stderr, "ID 0x%lx exceeded standard CAN ID range.\n",
123 (unsigned long)can_id);
127 canprio_rules[rules_count].can_id = can_id;
128 canprio_rules[rules_count].can_mask = (can_mask & CAN_SFF_MASK);
131 } else if (matches(*argv, "matcheid") == 0) { //Parse EFF ID
134 if (sscanf(*argv, "%"SCNx32 ":" "%"SCNx32, &can_id, &can_mask) != 2) {
135 fprintf(stderr, "improperly formed Can ID & mask '%s'\n", *argv);
139 if (can_id & ~CAN_EFF_MASK) {
140 fprintf(stderr, "ID 0x%lx exceeded extended CAN ID range.",
141 (unsigned long)can_id);
145 canprio_rules[rules_count].can_id = can_id | CAN_EFF_FLAG;
146 canprio_rules[rules_count].can_mask =
147 (can_mask & CAN_EFF_MASK) | CAN_EFF_FLAG;
150 } else if (matches(*argv, "classid") == 0 ||
151 strcmp(*argv, "flowid") == 0) {
152 //printf(" [parsing flowid]\n");
155 if (get_tc_classid(&handle, *argv)) {
156 fprintf(stderr, "Illegal \"classid\"\n");
159 addattr_l(n, MAX_MSG, TCA_CANPRIO_CLASSID, &handle, 4);
161 } else if (strcmp(*argv, "help") == 0) {
166 fprintf(stderr, "What is \"%s\"?\n", *argv);
173 addattr_l(n, MAX_MSG, TCA_CANPRIO_RULES, &canprio_rules,
174 sizeof(struct can_filter) * rules_count);
176 tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail;
180 /* When "tc filter show dev XY" is executed, function canprio_walk() (in kernel)
181 * is called (which calls canprio_dump() for each instance of a filter) which sends
182 * information about each instance of a filters to userspace -- to this function
183 * (which parses the message and prints it.
185 static int canprio_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
188 struct rtattr *tb[TCA_CANPRIO_MAX+1];
189 struct can_filter *canprio_rules = NULL;
196 parse_rtattr_nested(tb, TCA_CANPRIO_MAX, opt);
199 fprintf(f, "handle 0x%x ", handle);
202 if (tb[TCA_BASIC_CLASSID]) {
203 SPRINT_BUF(b1); //allocate buffer b1
204 fprintf(f, "flowid %s ",
205 sprint_tc_classid(*(__u32*)RTA_DATA(tb[TCA_BASIC_CLASSID]), b1));
208 if (tb[TCA_CANPRIO_RULES]) {
209 if (RTA_PAYLOAD(tb[TCA_CANPRIO_RULES]) < sizeof(struct can_filter))
212 canprio_rules = RTA_DATA(tb[TCA_CANPRIO_RULES]);
213 rules_count = (RTA_PAYLOAD(tb[TCA_CANPRIO_RULES]) / sizeof(struct can_filter));
215 for(i = 0; i < rules_count; i++) {
216 if (canprio_rules[i].can_id & CAN_EFF_FLAG) {
217 fprintf(f, "matcheid 0x%lx:0x%lx ",
218 (unsigned long)(canprio_rules[i].can_id & CAN_EFF_MASK),
219 (unsigned long)(canprio_rules[i].can_mask & CAN_EFF_MASK));
222 fprintf(f, "matchid 0x%lx:0x%lx ",
223 (unsigned long)(canprio_rules[i].can_id),
224 (unsigned long)(canprio_rules[i].can_mask));
233 struct filter_util canprio_filter_util = {
235 .parse_fopt = canprio_parse_opt,
236 .print_fopt = canprio_print_opt,