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

Reply via email to