Blame tc/em_canid.c

Packit d3f73b
/*
Packit d3f73b
 * em_canid.c  Ematch rule to match CAN frames according to their CAN identifiers
Packit d3f73b
 *
Packit d3f73b
 *             This program is free software; you can distribute it and/or
Packit d3f73b
 *             modify it under the terms of the GNU General Public License
Packit d3f73b
 *             as published by the Free Software Foundation; either version
Packit d3f73b
 *             2 of the License, or (at your option) any later version.
Packit d3f73b
 *
Packit d3f73b
 * Idea:       Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
Packit d3f73b
 * Copyright:  (c) 2011 Czech Technical University in Prague
Packit d3f73b
 *             (c) 2011 Volkswagen Group Research
Packit d3f73b
 * Authors:    Michal Sojka <sojkam1@fel.cvut.cz>
Packit d3f73b
 *             Pavel Pisa <pisa@cmp.felk.cvut.cz>
Packit d3f73b
 *             Rostislav Lisovy <lisovy@gmail.cz>
Packit d3f73b
 * Funded by:  Volkswagen Group Research
Packit d3f73b
 *
Packit d3f73b
 * Documentation: http://rtime.felk.cvut.cz/can/socketcan-qdisc-final.pdf
Packit d3f73b
 */
Packit d3f73b
Packit d3f73b
#include <stdio.h>
Packit d3f73b
#include <stdlib.h>
Packit d3f73b
#include <unistd.h>
Packit d3f73b
#include <fcntl.h>
Packit d3f73b
#include <sys/socket.h>
Packit d3f73b
#include <netinet/in.h>
Packit d3f73b
#include <arpa/inet.h>
Packit d3f73b
#include <string.h>
Packit d3f73b
#include <errno.h>
Packit d3f73b
#include <linux/can.h>
Packit d3f73b
#include <inttypes.h>
Packit d3f73b
#include "m_ematch.h"
Packit d3f73b
Packit d3f73b
#define EM_CANID_RULES_MAX 400 /* Main reason for this number is Nelink
Packit d3f73b
	message size limit equal to Single memory page size. When dump()
Packit d3f73b
	is invoked, there are even some ematch related headers sent from
Packit d3f73b
	kernel to userspace together with em_canid configuration --
Packit d3f73b
	400*sizeof(struct can_filter) should fit without any problems */
Packit d3f73b
Packit d3f73b
extern struct ematch_util canid_ematch_util;
Packit d3f73b
struct rules {
Packit d3f73b
	struct can_filter *rules_raw;
Packit d3f73b
	int rules_capacity;	/* Size of array allocated for rules_raw */
Packit d3f73b
	int rules_cnt;		/* Actual number of rules stored in rules_raw */
Packit d3f73b
};
Packit d3f73b
Packit d3f73b
static void canid_print_usage(FILE *fd)
Packit d3f73b
{
Packit d3f73b
	fprintf(fd,
Packit d3f73b
		"Usage: canid(IDLIST)\n" \
Packit d3f73b
		"where: IDLIST := IDSPEC [ IDLIST ]\n" \
Packit d3f73b
		"       IDSPEC := { ’sff’ CANID | ’eff’ CANID }\n" \
Packit d3f73b
		"       CANID := ID[:MASK]\n" \
Packit d3f73b
		"       ID, MASK := hexadecimal number (i.e. 0x123)\n" \
Packit d3f73b
		"Example: canid(sff 0x123 sff 0x124 sff 0x125:0xf)\n");
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
static int canid_parse_rule(struct rules *rules, struct bstr *a, int iseff)
Packit d3f73b
{
Packit d3f73b
	unsigned int can_id = 0;
Packit d3f73b
	unsigned int can_mask = 0;
Packit d3f73b
Packit d3f73b
	if (sscanf(a->data, "%"SCNx32 ":" "%"SCNx32, &can_id, &can_mask) != 2) {
Packit d3f73b
		if (sscanf(a->data, "%"SCNx32, &can_id) != 1) {
Packit d3f73b
			return -1;
Packit d3f73b
		} else {
Packit d3f73b
			can_mask = (iseff) ? CAN_EFF_MASK : CAN_SFF_MASK;
Packit d3f73b
		}
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	/* Stretch rules array up to EM_CANID_RULES_MAX if necessary */
Packit d3f73b
	if (rules->rules_cnt == rules->rules_capacity) {
Packit d3f73b
		if (rules->rules_capacity <= EM_CANID_RULES_MAX/2) {
Packit d3f73b
			rules->rules_capacity *= 2;
Packit d3f73b
			rules->rules_raw = realloc(rules->rules_raw,
Packit d3f73b
				sizeof(struct can_filter) * rules->rules_capacity);
Packit d3f73b
		} else {
Packit d3f73b
			return -2;
Packit d3f73b
		}
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	rules->rules_raw[rules->rules_cnt].can_id =
Packit d3f73b
		can_id | ((iseff) ? CAN_EFF_FLAG : 0);
Packit d3f73b
	rules->rules_raw[rules->rules_cnt].can_mask =
Packit d3f73b
		can_mask | CAN_EFF_FLAG;
Packit d3f73b
Packit d3f73b
	rules->rules_cnt++;
Packit d3f73b
Packit d3f73b
	return 0;
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
static int canid_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
Packit d3f73b
			  struct bstr *args)
Packit d3f73b
{
Packit d3f73b
	int iseff = 0;
Packit d3f73b
	int ret = 0;
Packit d3f73b
	struct rules rules = {
Packit d3f73b
		.rules_capacity = 25, /* Denominator of EM_CANID_RULES_MAX
Packit d3f73b
			Will be multiplied by 2 to calculate the size for realloc() */
Packit d3f73b
		.rules_cnt = 0
Packit d3f73b
	};
Packit d3f73b
Packit d3f73b
#define PARSE_ERR(CARG, FMT, ARGS...) \
Packit d3f73b
	em_parse_error(EINVAL, args, CARG, &canid_ematch_util, FMT, ##ARGS)
Packit d3f73b
Packit d3f73b
	if (args == NULL)
Packit d3f73b
		return PARSE_ERR(args, "canid: missing arguments");
Packit d3f73b
Packit d3f73b
	rules.rules_raw = calloc(rules.rules_capacity,
Packit d3f73b
				 sizeof(struct can_filter));
Packit d3f73b
Packit d3f73b
	do {
Packit d3f73b
		if (!bstrcmp(args, "sff")) {
Packit d3f73b
			iseff = 0;
Packit d3f73b
		} else if (!bstrcmp(args, "eff")) {
Packit d3f73b
			iseff = 1;
Packit d3f73b
		} else {
Packit d3f73b
			ret = PARSE_ERR(args, "canid: invalid key");
Packit d3f73b
			goto exit;
Packit d3f73b
		}
Packit d3f73b
Packit d3f73b
		args = bstr_next(args);
Packit d3f73b
		if (args == NULL) {
Packit d3f73b
			ret = PARSE_ERR(args, "canid: missing argument");
Packit d3f73b
			goto exit;
Packit d3f73b
		}
Packit d3f73b
Packit d3f73b
		ret = canid_parse_rule(&rules, args, iseff);
Packit d3f73b
		if (ret == -1) {
Packit d3f73b
			ret = PARSE_ERR(args, "canid: Improperly formed CAN ID & mask\n");
Packit d3f73b
			goto exit;
Packit d3f73b
		} else if (ret == -2) {
Packit d3f73b
			ret = PARSE_ERR(args, "canid: Too many arguments on input\n");
Packit d3f73b
			goto exit;
Packit d3f73b
		}
Packit d3f73b
	} while ((args = bstr_next(args)) != NULL);
Packit d3f73b
Packit d3f73b
	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
Packit d3f73b
	addraw_l(n, MAX_MSG, rules.rules_raw,
Packit d3f73b
		sizeof(struct can_filter) * rules.rules_cnt);
Packit d3f73b
Packit d3f73b
#undef PARSE_ERR
Packit d3f73b
exit:
Packit d3f73b
	free(rules.rules_raw);
Packit d3f73b
	return ret;
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
static int canid_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
Packit d3f73b
			  int data_len)
Packit d3f73b
{
Packit d3f73b
	struct can_filter *conf = data; /* Array with rules */
Packit d3f73b
	int rules_count;
Packit d3f73b
	int i;
Packit d3f73b
Packit d3f73b
	rules_count = data_len / sizeof(struct can_filter);
Packit d3f73b
Packit d3f73b
	for (i = 0; i < rules_count; i++) {
Packit d3f73b
		struct can_filter *pcfltr = &conf[i];
Packit d3f73b
Packit d3f73b
		if (pcfltr->can_id & CAN_EFF_FLAG) {
Packit d3f73b
			if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_EFF_MASK))
Packit d3f73b
				fprintf(fd, "eff 0x%"PRIX32,
Packit d3f73b
						pcfltr->can_id & CAN_EFF_MASK);
Packit d3f73b
			else
Packit d3f73b
				fprintf(fd, "eff 0x%"PRIX32":0x%"PRIX32,
Packit d3f73b
						pcfltr->can_id & CAN_EFF_MASK,
Packit d3f73b
						pcfltr->can_mask & CAN_EFF_MASK);
Packit d3f73b
		} else {
Packit d3f73b
			if (pcfltr->can_mask == (CAN_EFF_FLAG | CAN_SFF_MASK))
Packit d3f73b
				fprintf(fd, "sff 0x%"PRIX32,
Packit d3f73b
						pcfltr->can_id & CAN_SFF_MASK);
Packit d3f73b
			else
Packit d3f73b
				fprintf(fd, "sff 0x%"PRIX32":0x%"PRIX32,
Packit d3f73b
						pcfltr->can_id & CAN_SFF_MASK,
Packit d3f73b
						pcfltr->can_mask & CAN_SFF_MASK);
Packit d3f73b
		}
Packit d3f73b
Packit d3f73b
		if ((i + 1) < rules_count)
Packit d3f73b
			fprintf(fd, " ");
Packit d3f73b
	}
Packit d3f73b
Packit d3f73b
	return 0;
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
struct ematch_util canid_ematch_util = {
Packit d3f73b
	.kind = "canid",
Packit d3f73b
	.kind_num = TCF_EM_CANID,
Packit d3f73b
	.parse_eopt = canid_parse_eopt,
Packit d3f73b
	.print_eopt = canid_print_eopt,
Packit d3f73b
	.print_usage = canid_print_usage
Packit d3f73b
};