Blame tc/em_canid.c

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