/*************************************************************************
* (C) 2022 CloudSigma AG - Sofia/Bulgaria
* by Michael Pounov <misho@elwix.org>
**************************************************************************/
#include "fwsync.h"
MALLOC_DEFINE(M_FWSYNC, "fwsync_memory", "FWSync - memory");
static struct ipfw_sopt_handler soc[] = {
{ IP_FW_SYNC_XCONFIG, 0, HDIR_SET, fwsync_cfg },
{ IP_FW_SYNC_DESTROY, 0, HDIR_SET, fwsync_destroy },
{ IP_FW_SYNC_XGETCONFIG, 0, HDIR_GET, fwsync_get_cfg },
{ IP_FW_SYNC_LIST, 0, HDIR_GET, fwsync_list },
{ IP_FW_SYNC_START, 0, HDIR_SET, fwsync_start },
{ IP_FW_SYNC_STOP, 0, HDIR_SET, fwsync_stop },
};
static volatile int fwsync_hooked = 0;
struct fwsync_context fws_ctx = { 0 };
int fwsync_debug = DRV_DEBUG;
static struct sysctl_ctx_list fwsync_sysctl_ctx;
struct cfg_sync fws_cfg;
//static struct sysctl_oid *fws_sysctl_oid, *fws_sysctl_dir;
struct task fws_sndpkt_task;
struct taskqueue *fws_tq;
struct callout fws_co;
struct mtx fws_mtx_c, fws_mtx_e, fws_mtx_u;
fwsync_sndpkt_t fwsync_sndpkt, fwsync_updpkt;
SYSCTL_NODE(_net_inet_ip, IFT_FWSYNC, fwsync, CTLFLAG_RW, 0, "IPFW Sync - Sync firewall states");
SYSCTL_INT(_net_inet_ip_fwsync, OID_AUTO, debug, CTLFLAG_RW, &fwsync_debug, 0, "Debug driver");
static int
fws_fini(void *arg)
{
struct fws_sndpkt *p;
DTRACE();
if (!fwsync_hooked)
return EBUSY;
if (fws_cfg.cfg.on || fws_ctx.config) {
uprintf("Unable to unload ELWIX %s driver, cause you have active configuration.\n"
"Before unload driver flush configuration!\n", DRV_NAME);
return EBUSY;
}
IPFW_DEL_SOPT_HANDLER(1, soc);
callout_drain(&fws_co);
if (fws_tq) {
taskqueue_drain_all(fws_tq);
taskqueue_free(fws_tq);
}
mtx_lock(&fws_mtx_u);
while (!TAILQ_EMPTY(&fwsync_updpkt)) {
p = TAILQ_FIRST(&fwsync_updpkt);
TAILQ_REMOVE(&fwsync_updpkt, p, sp_next);
free(p, M_FWSYNC);
}
mtx_unlock(&fws_mtx_u);
mtx_lock(&fws_mtx_c);
while (!TAILQ_EMPTY(&fwsync_sndpkt)) {
p = TAILQ_FIRST(&fwsync_sndpkt);
TAILQ_REMOVE(&fwsync_sndpkt, p, sp_next);
free(p, M_FWSYNC);
}
mtx_unlock(&fws_mtx_c);
mtx_destroy(&fws_mtx_c);
mtx_destroy(&fws_mtx_e);
mtx_destroy(&fws_mtx_u);
fwsync_hooked = 0;
/* sysctl context */
sysctl_ctx_free(&fwsync_sysctl_ctx);
uprintf("Unloaded ELWIX %s driver version %d ...\n", DRV_NAME, DRV_VERSION);
return 0;
}
static int
fws_shut(void *arg)
{
DTRACE();
fws_fini(arg);
return 0;
}
static int
fws_init(void *arg)
{
DTRACE();
if (fwsync_hooked)
return 0;
memset(&fws_cfg, 0, sizeof fws_cfg);
memset(&fws_ctx, 0, sizeof fws_ctx);
TAILQ_INIT(&fwsync_sndpkt);
TAILQ_INIT(&fwsync_updpkt);
/* mutexes */
mtx_init(&fws_mtx_u, "fwsync mtx update", NULL, MTX_DEF);
mtx_init(&fws_mtx_e, "fwsync mtx edge", NULL, MTX_DEF);
mtx_init(&fws_mtx_c, "fwsync mtx collector", NULL, MTX_DEF);
/* taskqueue */
fws_tq = taskqueue_create("fwsync_tq", M_NOWAIT, taskqueue_thread_enqueue, &fws_tq);
if (!fws_tq) {
printf("Failed to allocate fwsync task queue\n");
mtx_destroy(&fws_mtx_c);
mtx_destroy(&fws_mtx_e);
return ENOMEM;
} else
taskqueue_start_threads(&fws_tq, 1, PI_NET, "fwsync tq");
TASK_INIT(&fws_sndpkt_task, 0, fwsync_sndpkt_handler, &fwsync_sndpkt);
/* callout */
callout_init_mtx(&fws_co, &fws_mtx_e, 0);
/* sysctl context */
sysctl_ctx_init(&fwsync_sysctl_ctx);
IPFW_ADD_SOPT_HANDLER(1, soc);
fwsync_hooked = 1;
uprintf("Loaded ELWIX %s driver version %d ...\n", DRV_NAME, DRV_VERSION);
return 0;
}
static int
fwsync_main(module_t m, int what, void *arg)
{
int ret = 0;
switch (what) {
case MOD_LOAD:
ret = fws_init(arg);
break;
case MOD_UNLOAD:
ret = fws_fini(arg);
break;
case MOD_SHUTDOWN:
ret = fws_shut(arg);
break;
case MOD_QUIESCE:
/* don't unload driver if there have configured driver */
if (fws_cfg.cfg.on || fws_ctx.config)
ret = EBUSY;
break;
default:
ret = EINVAL;
break;
}
return ret;
}
static moduledata_t fwsync_mod = {
"ipfw_sync",
fwsync_main,
NULL
};
DECLARE_MODULE(ipfw_sync, fwsync_mod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY);
MODULE_DEPEND(ipfw_sync, libalias, 1, 1, 1);
MODULE_DEPEND(ipfw_sync, ipfw, 3, 3, 3);
MODULE_VERSION(ipfw_sync, DRV_VERSION);
SYSINIT(fws_init, SI_SUB_PROTO_FIREWALL, (SI_ORDER_ANY - 128), fws_init, NULL);
SYSUNINIT(fws_fini, SI_SUB_PROTO_FIREWALL, (SI_ORDER_ANY - 128), fws_fini, NULL);
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>