216 lines
4.6 KiB
C
216 lines
4.6 KiB
C
/*
|
|
* ConnectCore 6UL tamper sample application.
|
|
*
|
|
* Copyright (c) 2016 Digi International Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Based on iio_event_monitor.c from the tools/iio directory, of the linux
|
|
* kernel.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
* the Free Software Foundation.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <linux/iio/events.h>
|
|
#include <linux/iio/types.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include "iio_utils.h"
|
|
|
|
#define TAMPER_SAMPLE_USAGE \
|
|
"Usage:\n" \
|
|
"tamper_sample -i tamper_iface\n\n"
|
|
|
|
#define TAMPER_SAMPLE_FULL_USAGE \
|
|
"Usage:\n" \
|
|
"tamper_sample [options]\n\n" \
|
|
"Options:\n" \
|
|
" -i : tamper interface to be used\n" \
|
|
" -h : help\n\n"
|
|
|
|
typedef struct mca_tamper {
|
|
struct iio_event_data event;
|
|
char *dev_name;
|
|
char *chrdev_name;
|
|
int iface;
|
|
int dev_num;
|
|
int event_fd;
|
|
} mca_tamper_t;
|
|
|
|
mca_tamper_t tamper_data;
|
|
|
|
static void show_usage(int full)
|
|
{
|
|
fprintf(stdout, "%s", full ?
|
|
TAMPER_SAMPLE_FULL_USAGE : TAMPER_SAMPLE_USAGE);
|
|
}
|
|
|
|
static bool event_is_tamper(struct iio_event_data *event)
|
|
{
|
|
enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
|
|
enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
|
|
enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
|
|
bool ret = true;
|
|
|
|
if (type != IIO_ACTIVITY)
|
|
ret = false;
|
|
else if (ev_type != IIO_EV_TYPE_CHANGE)
|
|
ret = false;
|
|
else if (dir != IIO_EV_DIR_NONE)
|
|
ret = false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void tamper_event_log(mca_tamper_t *tdata)
|
|
{
|
|
/* Log the event in the system log, if any */
|
|
fprintf(stdout, "tamper%d event! time: %lld\n",
|
|
tdata->iface, tdata->event.timestamp);
|
|
}
|
|
|
|
static void tamper_event_actions(mca_tamper_t *tdata)
|
|
{
|
|
/* Take the necessary defensive actions after a tamper event */
|
|
fprintf(stdout, "tamper%d: taking actions!\n", tdata->iface);
|
|
}
|
|
|
|
static void tamper_event_ack(mca_tamper_t *tdata)
|
|
{
|
|
int ret;
|
|
char *tamper_sysfs_dir;
|
|
|
|
ret = asprintf(&tamper_sysfs_dir,
|
|
"/sys/bus/iio/devices/iio:device%d",
|
|
tdata->dev_num);
|
|
if (ret < 0) {
|
|
fprintf(stdout, "Failed to build event ack file name\n");
|
|
return;
|
|
}
|
|
|
|
/* Finally, acknowledge the event */
|
|
ret = write_sysfs_int("tamper_events", tamper_sysfs_dir, 2);
|
|
if (ret < 0) {
|
|
fprintf(stdout, "Failed to acknowledge tamper%d event\n",
|
|
tdata->iface);
|
|
}
|
|
}
|
|
|
|
static void process_tamper_event(mca_tamper_t *tdata)
|
|
{
|
|
if (!event_is_tamper(&tdata->event)) {
|
|
fprintf(stdout, "Unknown event: time: %lld, id: %llx\n",
|
|
tdata->event.timestamp, tdata->event.id);
|
|
return;
|
|
}
|
|
|
|
tamper_event_log(tdata);
|
|
tamper_event_actions(tdata);
|
|
tamper_event_ack(tdata);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
mca_tamper_t *tdata = &tamper_data;
|
|
int ret;
|
|
int opt;
|
|
int fd;
|
|
|
|
memset(tdata, 0, sizeof(mca_tamper_t));
|
|
|
|
if (argc <= 1) {
|
|
show_usage(0);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
while ((opt = getopt(argc, argv, "i:h")) > 0) {
|
|
switch (opt) {
|
|
case 'i':
|
|
tdata->iface = atoi(optarg);
|
|
break;
|
|
|
|
case 'h':
|
|
show_usage(1);
|
|
return EXIT_SUCCESS;
|
|
|
|
default:
|
|
show_usage(0);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
ret = asprintf(&tdata->dev_name, "TAMPER%d", tdata->iface);
|
|
if (ret < 0) {
|
|
fprintf(stdout, "Failed to find interface, device name too long?\n");
|
|
ret = -ENOMEM;
|
|
goto error_ret;
|
|
}
|
|
|
|
tdata->dev_num = find_type_by_name(tdata->dev_name, "iio:device");
|
|
if (tdata->dev_num < 0) {
|
|
fprintf(stdout, "Failed to find iio:device for TAMPER%d\n",
|
|
tdata->iface);
|
|
ret = -ENODEV;
|
|
goto error_ret2;
|
|
}
|
|
|
|
ret = asprintf(&tdata->chrdev_name, "/dev/iio:device%d", tdata->dev_num);
|
|
if (ret < 0) {
|
|
fprintf(stdout, "Failed to allocate memory\n");
|
|
ret = -ENOMEM;
|
|
goto error_ret2;
|
|
}
|
|
|
|
fd = open(tdata->chrdev_name, 0);
|
|
if (fd < 0) {
|
|
fprintf(stdout, "Failed to open %s\n", tdata->chrdev_name);
|
|
ret = -errno;
|
|
goto error_ret3;
|
|
}
|
|
|
|
ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &tdata->event_fd);
|
|
|
|
close(fd);
|
|
|
|
if (ret < 0 || tdata->event_fd < 0) {
|
|
fprintf(stdout, "Failed to retrieve event fd\n");
|
|
ret = -errno;
|
|
goto error_ret3;
|
|
}
|
|
|
|
fprintf(stdout, "Waiting for tamper events:\n");
|
|
|
|
while (true) {
|
|
ret = read(tdata->event_fd, &tdata->event, sizeof(struct iio_event_data));
|
|
if (ret < 0) {
|
|
if (errno == EAGAIN) {
|
|
fprintf(stdout, "No events... continue\n");
|
|
continue;
|
|
} else {
|
|
perror("Failed to read event from device");
|
|
ret = -errno;
|
|
break;
|
|
}
|
|
}
|
|
|
|
process_tamper_event(tdata);
|
|
}
|
|
|
|
close(tdata->event_fd);
|
|
|
|
error_ret3:
|
|
free(tdata->chrdev_name);
|
|
error_ret2:
|
|
free(tdata->dev_name);
|
|
error_ret:
|
|
return ret;
|
|
}
|