From 30cd31fb69e2f7e8ce1b1b09a4b6f1f03cc81393 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 8 Sep 2010 11:59:00 +0200 Subject: [PATCH] Added a simple led plugin to control Linux LEDs based on IKE activity --- configure.in | 4 + src/libcharon/Makefile.am | 7 + src/libcharon/plugins/led/Makefile.am | 16 ++ src/libcharon/plugins/led/led_listener.c | 241 +++++++++++++++++++++++ src/libcharon/plugins/led/led_listener.h | 49 +++++ src/libcharon/plugins/led/led_plugin.c | 67 +++++++ src/libcharon/plugins/led/led_plugin.h | 42 ++++ 7 files changed, 426 insertions(+) create mode 100644 src/libcharon/plugins/led/Makefile.am create mode 100644 src/libcharon/plugins/led/led_listener.c create mode 100644 src/libcharon/plugins/led/led_listener.h create mode 100644 src/libcharon/plugins/led/led_plugin.c create mode 100644 src/libcharon/plugins/led/led_plugin.h diff --git a/configure.in b/configure.in index dbb8b84be..4c256cf4e 100644 --- a/configure.in +++ b/configure.in @@ -156,6 +156,7 @@ ARG_ENABL_SET([uci], [enable OpenWRT UCI configuration plugin.]) ARG_ENABL_SET([android], [enable Android specific plugin.]) ARG_ENABL_SET([nm], [enable NetworkManager plugin.]) ARG_ENABL_SET([ha], [enable high availability cluster plugin.]) +ARG_ENABL_SET([led], [enable plugin to control LEDs on IKEv2 activity using the Linux kernel LED subsystem.]) ARG_ENABL_SET([vstr], [enforce using the Vstr string library to replace glibc-like printf hooks.]) ARG_ENABL_SET([monolithic], [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.]) @@ -759,6 +760,7 @@ ADD_PLUGIN([nm], [c libcharon]) ADD_PLUGIN([dhcp], [c libcharon]) ADD_PLUGIN([android], [c libcharon]) ADD_PLUGIN([ha], [c libcharon]) +ADD_PLUGIN([led], [c libcharon]) ADD_PLUGIN([uci], [c libcharon]) ADD_PLUGIN([addrblock], [c libcharon]) ADD_PLUGIN([unit-tester], [c libcharon]) @@ -832,6 +834,7 @@ AM_CONDITIONAL(USE_DHCP, test x$dhcp = xtrue) AM_CONDITIONAL(USE_UNIT_TESTS, test x$unit_tests = xtrue) AM_CONDITIONAL(USE_LOAD_TESTER, test x$load_tester = xtrue) AM_CONDITIONAL(USE_HA, test x$ha = xtrue) +AM_CONDITIONAL(USE_LED, test x$led = xtrue) AM_CONDITIONAL(USE_EAP_SIM, test x$eap_sim = xtrue) AM_CONDITIONAL(USE_EAP_SIM_FILE, test x$eap_sim_file = xtrue) AM_CONDITIONAL(USE_EAP_SIMAKA_SQL, test x$eap_simaka_sql = xtrue) @@ -995,6 +998,7 @@ AC_OUTPUT( src/libcharon/plugins/addrblock/Makefile src/libcharon/plugins/uci/Makefile src/libcharon/plugins/ha/Makefile + src/libcharon/plugins/led/Makefile src/libcharon/plugins/android/Makefile src/libcharon/plugins/stroke/Makefile src/libcharon/plugins/updown/Makefile diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index ef5f9f499..5b5bd1dc4 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -354,6 +354,13 @@ if MONOLITHIC endif endif +if USE_LED + SUBDIRS += plugins/led +if MONOLITHIC + libcharon_la_LIBADD += plugins/led/libstrongswan-led.la +endif +endif + if USE_UCI SUBDIRS += plugins/uci if MONOLITHIC diff --git a/src/libcharon/plugins/led/Makefile.am b/src/libcharon/plugins/led/Makefile.am new file mode 100644 index 000000000..6428361fc --- /dev/null +++ b/src/libcharon/plugins/led/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-led.la +else +plugin_LTLIBRARIES = libstrongswan-led.la +endif + +libstrongswan_led_la_SOURCES = led_plugin.h led_plugin.c \ + led_listener.h led_listener.c + +libstrongswan_led_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/led/led_listener.c b/src/libcharon/plugins/led/led_listener.c new file mode 100644 index 000000000..18def8005 --- /dev/null +++ b/src/libcharon/plugins/led/led_listener.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "led_listener.h" + +#include + +#include +#include +#include + +typedef struct private_led_listener_t private_led_listener_t; + +/** + * Private data of an led_listener_t object. + */ +struct private_led_listener_t { + + /** + * Public led_listener_t interface. + */ + led_listener_t public; + + /** + * Mutex + */ + mutex_t *mutex; + + /** + * Number of established IKE_SAs + */ + int count; + + /** + * LED blink on/off time, in ms + */ + int blink_time; + + /** + * Activity LED fd, if any + */ + FILE *activity; + + /** + * Activity LED maximum brightness + */ + int activity_max; +}; + +/** + * Open a LED brightness control file, get max brightness + */ +static FILE *open_led(char *name, int *max_brightness) +{ + char path[PATH_MAX]; + FILE *f; + + if (!name) + { + return NULL; + } + + *max_brightness = 1; + snprintf(path, sizeof(path), "/sys/class/leds/%s/max_brightness", name); + f = fopen(path, "r"); + if (f) + { + if (fscanf(f, "%d\n", max_brightness) != 1) + { + DBG1(DBG_CFG, "reading max brightness for '%s' failed: %s, using 1", + name, strerror(errno)); + } + fclose(f); + } + else + { + DBG1(DBG_CFG, "reading max_brightness for '%s' failed: %s, using 1", + name, strerror(errno)); + } + + snprintf(path, sizeof(path), "/sys/class/leds/%s/brightness", name); + f = fopen(path, "w"); + if (!f) + { + DBG1(DBG_CFG, "opening LED file '%s' failed: %s", path, strerror(errno)); + } + return f; +} + +/** + * Set a LED to a given brightness + */ +static void set_led(FILE *led, int brightness) +{ + if (led) + { + if (fprintf(led, "%d\n", brightness) <= 0 || + fflush(led) != 0) + { + DBG1(DBG_CFG, "setting LED brightness failed: %s", strerror(errno)); + } + } +} + +/** + * Plugin unloaded? + */ +static bool plugin_gone = FALSE; + +/** + * Reset activity LED after timeout + */ +static job_requeue_t reset_activity_led(private_led_listener_t *this) +{ + if (!plugin_gone) + { /* TODO: fix race */ + this->mutex->lock(this->mutex); + if (this->count) + { + set_led(this->activity, this->activity_max); + } + else + { + set_led(this->activity, 0); + } + this->mutex->unlock(this->mutex); + } + return JOB_REQUEUE_NONE; +} + +/** + * Blink the activity LED + */ +static void blink_activity(private_led_listener_t *this) +{ + if (this->activity) + { + this->mutex->lock(this->mutex); + if (this->count) + { + set_led(this->activity, 0); + } + else + { + set_led(this->activity, this->activity_max); + } + lib->scheduler->schedule_job_ms(lib->scheduler, + (job_t*)callback_job_create((callback_job_cb_t)reset_activity_led, + this, NULL, NULL), this->blink_time); + this->mutex->unlock(this->mutex); + } +} + +METHOD(listener_t, ike_state_change, bool, + private_led_listener_t *this, ike_sa_t *ike_sa, ike_sa_state_t state) +{ + this->mutex->lock(this->mutex); + if (state == IKE_ESTABLISHED && ike_sa->get_state(ike_sa) != IKE_ESTABLISHED) + { + this->count++; + if (this->count == 1) + { + set_led(this->activity, this->activity_max); + } + } + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && state != IKE_ESTABLISHED) + { + this->count--; + if (this->count == 0) + { + set_led(this->activity, 0); + } + } + this->mutex->unlock(this->mutex); + return TRUE; +} + +METHOD(listener_t, message_hook, bool, + private_led_listener_t *this, ike_sa_t *ike_sa, + message_t *message, bool incoming) +{ + if (incoming || message->get_request(message)) + { + blink_activity(this); + } + return TRUE; +} + +METHOD(led_listener_t, destroy, void, + private_led_listener_t *this) +{ + this->mutex->lock(this->mutex); + set_led(this->activity, 0); + plugin_gone = TRUE; + this->mutex->unlock(this->mutex); + if (this->activity) + { + fclose(this->activity); + } + this->mutex->destroy(this->mutex); + free(this); +} + +/** + * See header + */ +led_listener_t *led_listener_create() +{ + private_led_listener_t *this; + + INIT(this, + .public = { + .listener = { + .ike_state_change = _ike_state_change, + .message = _message_hook, + }, + .destroy = _destroy, + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .blink_time = lib->settings->get_int(lib->settings, + "charon.plugins.led.blink_time", 50), + ); + + this->activity = open_led(lib->settings->get_str(lib->settings, + "charon.plugins.led.activity_led", NULL), &this->activity_max); + set_led(this->activity, 0); + + return &this->public; +} diff --git a/src/libcharon/plugins/led/led_listener.h b/src/libcharon/plugins/led/led_listener.h new file mode 100644 index 000000000..74af5bf05 --- /dev/null +++ b/src/libcharon/plugins/led/led_listener.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup led_listener led_listener + * @{ @ingroup led + */ + +#ifndef LED_LISTENER_H_ +#define LED_LISTENER_H_ + +#include + +typedef struct led_listener_t led_listener_t; + +/** + * Listener to register the set of IPs we spoof ARP responses for. + */ +struct led_listener_t { + + /** + * Implements listener_t interface. + */ + listener_t listener; + + /** + * Destroy a led_listener_t. + */ + void (*destroy)(led_listener_t *this); +}; + +/** + * Create a led_listener instance. + */ +led_listener_t *led_listener_create(); + +#endif /** LED_LISTENER_H_ @}*/ diff --git a/src/libcharon/plugins/led/led_plugin.c b/src/libcharon/plugins/led/led_plugin.c new file mode 100644 index 000000000..322d198ff --- /dev/null +++ b/src/libcharon/plugins/led/led_plugin.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "led_plugin.h" + +#include "led_listener.h" + +#include + +typedef struct private_led_plugin_t private_led_plugin_t; + +/** + * private data of led plugin + */ +struct private_led_plugin_t { + + /** + * implements plugin interface + */ + led_plugin_t public; + + /** + * Listener controlling LEDs + */ + led_listener_t *listener; +}; + +METHOD(plugin_t, destroy, void, + private_led_plugin_t *this) +{ + charon->bus->remove_listener(charon->bus, &this->listener->listener); + this->listener->destroy(this->listener); + free(this); +} + +/** + * Plugin constructor + */ +plugin_t *led_plugin_create() +{ + private_led_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .destroy = _destroy, + }, + }, + .listener = led_listener_create(), + ); + + charon->bus->add_listener(charon->bus, &this->listener->listener); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/led/led_plugin.h b/src/libcharon/plugins/led/led_plugin.h new file mode 100644 index 000000000..a7449addd --- /dev/null +++ b/src/libcharon/plugins/led/led_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup led led + * @ingroup cplugins + * + * @defgroup led_plugin led_plugin + * @{ @ingroup led + */ + +#ifndef LED_PLUGIN_H_ +#define LED_PLUGIN_H_ + +#include + +typedef struct led_plugin_t led_plugin_t; + +/** + * Linux LED control based on IKE activity/state. + */ +struct led_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** LED_PLUGIN_H_ @}*/