From: Daniel Wagner <daniel.wag...@bmw-carit.de> --- src/connman.h | 24 +++++++ src/nfacct.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+)
diff --git a/src/connman.h b/src/connman.h index 9c8fbc6..89c0675 100644 --- a/src/connman.h +++ b/src/connman.h @@ -926,6 +926,30 @@ void __connman_netfilter_cancel(unsigned int id); int __connman_netfilter_init(void); void __connman_netfilter_cleanup(void); +struct nfacct_context; + +typedef void (* connman_nfacct_enable_cb_t) (int error, + struct nfacct_context *ctx, + void *user_data); +typedef void (* connman_nfacct_disable_cb_t) (int error, + struct nfacct_context *ctx, + void *user_data); +typedef void (* connman_nfacct_stats_cb_t) (struct nfacct_context *ctx, + uint64_t packets, + uint64_t bytes, + void *user_data); + +struct nfacct_context *__connman_nfacct_create_context(void); +void __connman_nfacct_destroy_context(struct nfacct_context *ctx); +int __connman_nfacct_add(struct nfacct_context *ctx, const char *name, + connman_nfacct_stats_cb_t cb, + void *user_data); +int __connman_nfacct_enable(struct nfacct_context *ctx, + connman_nfacct_enable_cb_t cb, + void *user_data); +int __connman_nfacct_disable(struct nfacct_context *ctx, + connman_nfacct_disable_cb_t cb, + void *user_data); typedef int (* connman_nfacct_flush_cb_t) (int error, void *user_data); diff --git a/src/nfacct.c b/src/nfacct.c index b24cc30..ef6fbf0 100644 --- a/src/nfacct.c +++ b/src/nfacct.c @@ -27,11 +27,228 @@ #include "connman.h" +struct nfacct_rule { + char *name; + connman_nfacct_stats_cb_t cb; + void *user_data; +}; + +struct nfacct_context { + GList *rules; + unsigned int pending; + int error; +}; + struct nfacct_flush { unsigned int pending; int error; }; +static void cleanup_nfacct_rule(gpointer user_data) +{ + struct nfacct_rule *rule = user_data; + + g_free(rule->name); + g_free(rule); +} + +struct nfacct_context *__connman_nfacct_create_context(void) +{ + struct nfacct_context *ctx; + + ctx = g_new0(struct nfacct_context, 1); + + return ctx; +} + +void __connman_nfacct_destroy_context(struct nfacct_context *ctx) +{ + g_list_free_full(ctx->rules, cleanup_nfacct_rule); + g_free(ctx); +} + +int __connman_nfacct_add(struct nfacct_context *ctx, const char *name, + connman_nfacct_stats_cb_t cb, + void *user_data) +{ + struct nfacct_rule *rule = g_new0(struct nfacct_rule, 1); + + rule->name = g_strdup(name); + rule->cb = cb; + rule->user_data = user_data; + + ctx->rules = g_list_append(ctx->rules, rule); + + return 0; +} + +static void nfacct_enable_failed_cb(int error, void *user_data) +{ + struct cb_data *cbd = user_data; + connman_nfacct_enable_cb_t cb = cbd->cb; + struct nfacct_context *ctx = cbd->data; + + DBG(""); + + user_data = cbd->user_data; + g_free(cbd); + + ctx->pending--; + + if (ctx->pending > 0) + return; + + cb(ctx->error, ctx, user_data); +} + +static void nfacct_handle_enable_error(struct nfacct_context *ctx, + connman_nfacct_enable_cb_t cb, + void *user_data) +{ + struct cb_data *cbd; + struct nfacct_rule *rule; + GList *list; + unsigned int id; + + DBG(""); + + for (list = ctx->rules; list != NULL; list = list->next) { + rule = list->data; + + DBG("%s", rule->name); + cbd = cb_data_new(cb, user_data); + cbd->data = ctx; + id = __connman_netfilter_acct_del(rule->name, + nfacct_enable_failed_cb, cbd); + if (id == 0) { + g_free(cbd); + continue; + } + + ctx->pending++; + } +} + +static void nfacct_enable_cb(int error, void *user_data) +{ + struct cb_data *cbd = user_data; + connman_nfacct_enable_cb_t cb = cbd->cb; + struct nfacct_context *ctx = cbd->data; + + DBG("error %d pending %d", error, ctx->pending); + + user_data = cbd->user_data; + g_free(cbd); + + ctx->pending--; + + if (error < 0) + ctx->error = error; + + if (ctx->pending > 0) + return; + + if (ctx->error < 0) { + nfacct_handle_enable_error(ctx, cb, user_data); + return; + } + + cb(0, ctx, user_data); +} + +static void nfacct_disable_cb(int error, void *user_data) +{ + struct cb_data *cbd = user_data; + connman_nfacct_disable_cb_t cb = cbd->cb; + struct nfacct_context *ctx = cbd->data; + + DBG("error %d pending %d", error, ctx->pending); + + user_data = cbd->user_data; + g_free(cbd); + + ctx->pending--; + + if (error < 0) + ctx->error = error; + + if (ctx->pending > 0) + return; + + cb(ctx->error, ctx, user_data); +} + +int __connman_nfacct_enable(struct nfacct_context *ctx, + connman_nfacct_enable_cb_t cb, + void *user_data) +{ + struct cb_data *cbd; + struct nfacct_rule *rule; + GList *list; + unsigned int id; + + DBG(""); + + for (list = ctx->rules; list != NULL; list = list->next) { + rule = list->data; + + DBG("%s", rule->name); + + cbd = cb_data_new(cb, user_data); + cbd->data = ctx; + id = __connman_netfilter_acct_new(rule->name, nfacct_enable_cb, + cbd); + if (id == 0) + goto err; + + ctx->pending++; + } + + return 0; + +err: + if (ctx->pending > 0) { + ctx->error = -ECOMM; + return 0; + } + + g_free(cbd); + + return -ECOMM; +} + +int __connman_nfacct_disable(struct nfacct_context *ctx, + connman_nfacct_disable_cb_t cb, + void *user_data) +{ + struct cb_data *cbd; + struct nfacct_rule *rule; + GList *list; + unsigned int id; + int err = 0; + + DBG(""); + + for (list = ctx->rules; list != NULL; list = list->next) { + rule = list->data; + + DBG("%s", rule->name); + cbd = cb_data_new(cb, user_data); + cbd->data = ctx; + id = __connman_netfilter_acct_del(rule->name, nfacct_disable_cb, + cbd); + if (id == 0) { + err = -ECOMM; + g_free(cbd); + continue; + } + + ctx->pending++; + } + + return err; +} + static void nfacct_flush_del_cb(int error, void *user_data) { struct cb_data *cbd = user_data; -- 1.8.1.3.566.gaa39828 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman