From: Daniel Wagner <[email protected]>
---
src/connman.h | 24 +++++++
src/nfacct.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 241 insertions(+)
diff --git a/src/connman.h b/src/connman.h
index 0f98e4d..37ec520 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -933,6 +933,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.2.rc3.16.gce432ca
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman