Send connman mailing list submissions to
[email protected]
To subscribe or unsubscribe via email, send a message with subject or
body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of connman digest..."
Today's Topics:
1. Re: [PATCH] Add support to get or remove known services via command /
(Daniel Wagner)
2. Re: Manual removal of service provisioning settings
(Daniel Wagner)
3. [PATCH] IP Accounting for WiFi Clients (Aravind Gunasekaran)
----------------------------------------------------------------------
Date: Wed, 27 May 2020 11:53:51 +0200
From: Daniel Wagner <[email protected]>
Subject: Re: [PATCH] Add support to get or remove known services via
command /
To: [email protected]
Cc: "Ryll, Jan (BSH)" <[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
Hi Jan,
Sorry for the long delay. It got drawned in my inbox. Maybe next time, you could
directly post this to mailing list.
On Wed, May 27, 2020 at 08:53:06AM +0200, Daniel Wagner wrote:
> From: "Ryll, Jan (BSH)" <[email protected]>
>
> ---
>
> I'v recieved this patch directly into my inbox...
>
> client/commands.c | 56 +++++++++++++++++++++++++++++++++++
> src/connman.h | 2 ++
> src/manager.c | 63 ++++++++++++++++++++++++++++++++++++++++
> src/service.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++
> tools/manager-api.c | 84
> +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 285 insertions(+)
>
> diff --git a/client/commands.c b/client/commands.c
> index 05b9316..594f375 100644
> --- a/client/commands.c
> +++ b/client/commands.c
> @@ -389,6 +389,58 @@ static int cmd_services(char *args[], int num, struct
> connman_option *options)
> object_properties, path, NULL, NULL);
> }
>
> +static int cmd_known_services(char *args[], int num, struct connman_option
> *options)
> +{
> + if (num > 1)
> + return -E2BIG;
> +
> + return __connmanctl_dbus_method_call(connection,
> + CONNMAN_SERVICE, CONNMAN_PATH,
> + "net.connman.Manager",
> + "GetKnownServices",
> + services_list, NULL, NULL, NULL);
> +}
> +
> +
> +static int remove_known_service_return(DBusMessageIter *iter, const char
> *error,
> + void *user_data)
> +{
> + char *path = user_data;
> +
> + if (!error) {
> + char *str = strrchr(path, '/');
> + str++;
> + fprintf(stdout, "Removed %s\n", str);
> + } else
> + fprintf(stderr, "Error %s: %s\n", path, error);
> +
> + g_free(user_data);
> +
> + return 0;
> +}
> +
> +static int cmd_remove_known_service(char *args[], int num, struct
> connman_option *options)
> +{
> + char *path_of_service_to_remove;
> +
> + if (num > 2)
> + return -E2BIG;
> +
> + if (num < 2)
> + return -EINVAL;
> +
> + if (check_dbus_name(args[1]) == false)
> + return -EINVAL;
> +
> + path_of_service_to_remove = g_strdup_printf("%s", args[1]);
> +
> + return __connmanctl_dbus_method_call(connection,
> + CONNMAN_SERVICE, CONNMAN_PATH,
> + "net.connman.Manager",
> + "RemoveKnownService",
> + remove_known_service_return,
> path_of_service_to_remove, NULL, NULL);
> +}
> +
> static int cmd_peers(char *args[], int num, struct connman_option *options)
> {
> char *peer_name = NULL;
> @@ -2738,6 +2790,10 @@ static const struct {
> lookup_tether },
> { "services", "[<service>]", service_options, cmd_services,
> "Display services", lookup_service_arg },
> + { "known-services", NULL, NULL, cmd_known_services,
> + "Display known services", NULL },
> + { "remove-known-service", "<service>", NULL,
> + cmd_remove_known_service, "Remove known service", NULL },
Align the members like below.
> { "peers", "[peer]", NULL, cmd_peers,
> "Display peers", lookup_peer_arg },
> { "scan", "<technology>", NULL, cmd_scan,
> diff --git a/src/connman.h b/src/connman.h
> index 82e77d3..bb01385 100644
> --- a/src/connman.h
> +++ b/src/connman.h
> @@ -665,6 +665,7 @@ int __connman_service_init(void);
> void __connman_service_cleanup(void);
> int __connman_service_load_modifiable(struct connman_service *service);
>
> +void __connman_known_service_list_struct(DBusMessageIter *iter);
> void __connman_service_list_struct(DBusMessageIter *iter);
>
> int __connman_service_compare(const struct connman_service *a,
> @@ -739,6 +740,7 @@ int __connman_service_disconnect_all(void);
> void __connman_service_set_active_session(bool enable, GSList *list);
> void __connman_service_auto_connect(enum connman_service_connect_reason
> reason);
> bool __connman_service_remove(struct connman_service *service);
> +bool __connman_service_remove_known_service(const char *path);
> bool __connman_service_is_provider_pending(struct connman_service *service);
> void __connman_service_set_provider_pending(struct connman_service *service,
> DBusMessage *msg);
> diff --git a/src/manager.c b/src/manager.c
> index d15ce20..7c6ff14 100644
> --- a/src/manager.c
> +++ b/src/manager.c
> @@ -175,6 +175,11 @@ static struct connman_notifier technology_notifier = {
> .idle_state = idle_state,
> };
>
> +static void append_known_service_structs(DBusMessageIter *iter, void
> *user_data)
> +{
> + __connman_known_service_list_struct(iter);
> +}
> +
> static void append_service_structs(DBusMessageIter *iter, void *user_data)
> {
> __connman_service_list_struct(iter);
> @@ -195,6 +200,58 @@ static DBusMessage *get_services(DBusConnection *conn,
> return reply;
> }
>
> +static DBusMessage *get_known_services(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + DBusMessage *reply;
> +
> + reply = dbus_message_new_method_return(msg);
> + if (!reply)
> + return NULL;
> +
> + __connman_dbus_append_objpath_dict_array(reply,
> + append_known_service_structs, NULL);
> +
> + return reply;
> +}
> +
> +static DBusMessage *remove_known_service(DBusConnection *conn,
> + DBusMessage *msg, void *data)
> +{
> + DBusMessage *reply;
> + const char *path;
> + int err;
> +
> + reply = dbus_message_new_method_return(msg);
> + if (!reply)
> + return NULL;
> +
> + /* get path */
> + dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
> + DBUS_TYPE_INVALID);
> +
> + /* extract service */
> + char *str = strrchr(path, '/');
All variable desclartion go fist.
> + if(NULL == str)
> + {
> + return __connman_error_failed(msg, -ENOENT);
> + }
We use a different style in ConnMan. See doc/coding-style.txt
if (!str)
return __connman_error_failed(msg, -ENOENT);
> + str++;
> + if(0 >= strlen(str))
if (!strlen(str))
return __connman_error_failed(msg, -ENOENT);
note strlen() returns a size_t which can't be negative. So you just need to test
for a empty string.
> + {
> + return __connman_error_failed(msg, -ENOENT);
> + }
> +
> + DBG("Service to remove [%s]", str);
> +
> + if (!__connman_service_remove_known_service(str))
> + {
> + return __connman_error_failed(msg, -ENOENT);
> + }
> +
> + return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> +}
> +
> static void append_peer_structs(DBusMessageIter *iter, void *user_data)
> {
> __connman_peer_list_struct(iter);
> @@ -513,6 +570,12 @@ static const GDBusMethodTable manager_methods[] = {
> { GDBUS_DEPRECATED_METHOD("RemoveProvider",
> GDBUS_ARGS({ "provider", "o" }), NULL,
> remove_provider) },
> + { GDBUS_METHOD("GetKnownServices",
> + NULL, GDBUS_ARGS({"knownServices", "a(oa{sv})" }),
> + get_known_services) },
> + { GDBUS_METHOD("RemoveKnownService",
> + GDBUS_ARGS({ "path", "o" }), NULL,
> + remove_known_service) },
> { GDBUS_METHOD("GetServices",
> NULL, GDBUS_ARGS({ "services", "a(oa{sv})" }),
> get_services) },
> diff --git a/src/service.c b/src/service.c
> index 733c072..5de7974 100644
> --- a/src/service.c
> +++ b/src/service.c
> @@ -2577,6 +2577,79 @@ static void append_struct(gpointer value, gpointer
> user_data)
> append_struct_service(iter, append_dict_properties, service);
> }
>
> +void __connman_known_service_list_struct(DBusMessageIter *iter)
> +{
> + gchar **services = NULL;
> + gchar **serviceIDParts = NULL;
no cammel case
> + int i = 0;
> + struct connman_service *service = NULL;
Reorder the variable decklartions. We usually try to do a reverse christmas
tree style. But use your jugment.
> +
> + DBG("listing known services");
Just a DBG("") will do the job, since the function name is in the log.
> +
> + services = connman_storage_get_services();
> + if (services == NULL)
if (!service)
> + return;
> +
> + for (i = 0; i < g_strv_length(services); i++)
> + {
for (...) {
> + service = connman_service_create();
> + if (service == NULL)
if (!service) {
> + {
> + connman_error("connman_service_create() allocation
> failed");
> + return ;
> + }
> + service->identifier = g_strdup(services[i]);
> + serviceIDParts = g_strsplit(services[i], "_",
> + -1);
white space damage.
> + if (serviceIDParts != NULL)
> + {
try to avoid indention levels like this one.
if (!var)
continue;
> + service->type =
> +
> __connman_service_string2type(serviceIDParts[0]);
> + service->path =
> + g_strdup_printf("%s/service/%s", CONNMAN_PATH,
> service->identifier);
> + if (service->type ==
> + CONNMAN_SERVICE_TYPE_WIFI)
fits on one line
> + service->security =
> +
> __connman_service_string2security(serviceIDParts[g_strv_length(serviceIDParts)
> - 1]);
> +
> + if (service->path != NULL)
> + {
> +
> + if (find_service(service->path) != NULL)
> +
> + service->state =
> (find_service(service->path))->state;
> + if (service->type ==
> + CONNMAN_SERVICE_TYPE_ETHERNET &&
> + find_service(service->path) != NULL)
> +
> + service->name =
> (find_service(service->path))->name;
> +
> + if (0 !=
> + service_load(service))
> + {
> +
> + connman_error("service_load() returned
> error");
> +
> + g_free(service);
> +
> + g_strfreev(serviceIDParts);
> +
> + g_strfreev(services);
> + return;
> + }
> +
> + append_struct_service(iter,
> +
> append_dict_properties, service);
> + }
this whole block needs reformat. lot's of unneserray newlines.
> +
> + g_strfreev(serviceIDParts);
> + }
> + g_free(service);
> + }
> +
> + g_strfreev(services);
> +}
> +
> void __connman_service_list_struct(DBusMessageIter *iter)
> {
> g_list_foreach(service_list, append_struct, iter);
> @@ -4406,6 +4479,13 @@ bool __connman_service_remove(struct connman_service
> *service)
> return true;
> }
>
> +bool __connman_service_remove_known_service(const char *path)
> +{
> + DBG("Remove known service [%s]", path);
I tend to say we shouldn't add to many DBG and log function for this.
Please try to add only one for the whole operation. We don't want
to jam the log even more.
> +
> + return __connman_storage_remove_service(path);
> +}
> +
> static DBusMessage *remove_service(DBusConnection *conn,
> DBusMessage *msg, void *user_data)
> {
> diff --git a/tools/manager-api.c b/tools/manager-api.c
> index e082962..b1291c6 100644
> --- a/tools/manager-api.c
> +++ b/tools/manager-api.c
> @@ -64,6 +64,90 @@ static DBusMessage *set_property(DBusConnection
> *connection,
> return reply;
> }
>
> +DBusMessage *manager_get_known_services(DBusConnection *connection)
> +{
> + DBusMessage *message, *reply;
> + DBusError error;
> +
> + message = dbus_message_new_method_call(CONNMAN_SERVICE,
> + CONNMAN_MANAGER_PATH,
> + CONNMAN_MANAGER_INTERFACE,
> + "GetKnownServices");
> +
> + if (!message)
> + return NULL;
> +
> + dbus_error_init(&error);
> +
> + reply = dbus_connection_send_with_reply_and_block(connection,
> + message, -1, &error);
> + if (!reply)
> + {
> + if (dbus_error_is_set(&error))
> + {
> + LOG("%s", error.message);
> + dbus_error_free(&error);
> + }
> + else
> + {
> + LOG("Failed to get known services");
> + }
> + dbus_message_unref(message);
> + return NULL;
> + }
this needs a reformat as documented in coding-style.txt
> +
> + dbus_message_unref(message);
> +
> + return reply;
> +}
> +
> +DBusMessage *manager_remove_known_service(DBusConnection *connection,
> + const char
> *service_path)
> +{
> + DBusMessage *message, *reply;
> + DBusError error;
> + DBusMessageIter array;
> +
> + DBG("Service path to remove [%s]", service_path);
> +
> + message = dbus_message_new_method_call(CONNMAN_SERVICE,
> + CONNMAN_MANAGER_PATH,
> + CONNMAN_MANAGER_INTERFACE,
> + "RemoveKnownService");
> +
> + if (!message)
> + return NULL;
> +
> + dbus_error_init(&error);
> +
> + dbus_message_iter_init_append(message, &array);
> +
> + dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
> + &service_path);
> +
> + reply = dbus_connection_send_with_reply_and_block(connection,
> + message, -1, &error);
> +
> + if (!reply)
> + {
> + if (dbus_error_is_set(&error))
> + {
> + LOG("%s", error.message);
> + dbus_error_free(&error);
> + }
> + else
> + {
> + LOG("Failed to get known services");
> + }
> + dbus_message_unref(message);
> + return NULL;
> + }
same goes here
> +
> + dbus_message_unref(message);
> +
> + return reply;
> +}
> +
> DBusMessage *manager_get_services(DBusConnection *connection)
> {
> DBusMessage *message, *reply;
The logic part is straight forward and looks good to me. Apart the style
issues, I'd like also to have a documentation update on the API change
(doc/manager-api.txt).
Thanks,
Daniel
------------------------------
Date: Wed, 27 May 2020 11:55:15 +0200
From: Daniel Wagner <[email protected]>
Subject: Re: Manual removal of service provisioning settings
To: "Ryll, Jan (GED-SDD2)" <[email protected]>
Cc: "[email protected]" <[email protected]>,
"[email protected]" <[email protected]>
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii
Hi Jan,
On Wed, May 27, 2020 at 07:01:24AM +0000, Ryll, Jan (GED-SDD2) wrote:
> I am using this patch within our project since half a year and it works for
> our project.
Nice, tested patches are always a good thing!
> @Daniel: Could you tell me what to clean up to bring it into connman?
Sure, just posted a quick review.
Thanks,
Daniel
------------------------------
Date: Wed, 27 May 2020 15:33:20 +0530
From: Aravind Gunasekaran <[email protected]>
Subject: [PATCH] IP Accounting for WiFi Clients
To: Daniel Wagner <[email protected]>, [email protected]
Message-ID:
<CAJ0PF7ejJ21Gvu97DDFve2JGEqwSN8-5SWYnu0=yp+253k+...@mail.gmail.com>
Content-Type: multipart/alternative;
boundary="000000000000ff5ca605a69e52b6"
--000000000000ff5ca605a69e52b6
Content-Type: text/plain; charset="UTF-8"
diff --git a/Makefile.am b/Makefile.am
old mode 100644
new mode 100755
index 5971ca9..44148df
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@ include_HEADERS = include/log.h include/plugin.h \
include/storage.h include/provision.h \
include/session.h include/ipaddress.h include/agent.h \
include/inotify.h include/peer.h include/machine.h \
- include/acd.h include/tethering.h
+ include/acd.h include/tethering.h include/accounting-iptables.h
nodist_include_HEADERS = include/version.h
@@ -152,7 +152,7 @@ src_connmand_wait_online_LDADD = gdbus/
libgdbus-internal.la \
@GLIB_LIBS@ @DBUS_LIBS@
if XTABLES
-src_connmand_SOURCES += src/iptables.c src/firewall-iptables.c
+src_connmand_SOURCES += src/iptables.c src/firewall-iptables.c
src/accounting-iptables.c
src_connmand_LDADD += @XTABLES_LIBS@
endif
diff --git a/include/accounting-iptables.h b/include/accounting-iptables.h
new file mode 100755
index 0000000..3a9cc30
--- /dev/null
+++ b/include/accounting-iptables.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
+ *
+ */
+
+#ifndef __CONNMAN_ACCOUNTING_IPTABLES_H
+#define __CONNMAN_ACCOUNTING_IPTABLES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct counters {
+ __u64 pcnt, bcnt; /* Packet and byte counters */
+};
+
+struct ip_accounting_info {
+ char *ipv4_address; /* IP address of the client */
+ struct counters egress; /* Transmitted bytes information of the client */
+ struct counters ingress; /* Received bytes information of the client */
+};
+
+int __connman_get_ip_acc_info(struct ip_accounting_info *ip_acc);
+int __connman_add_ip_acc_rules(char *ip_addrs);
+int __connman_delete_ip_acc_rules(char *ip_addrs);
+int __connman_create_ip_acc_chain(char *ifname);
+int __connman_destroy_ip_acc_chain(char *ifname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_ACCOUNTING_IPTABLES_H */
diff --git a/src/accounting-iptables.c b/src/accounting-iptables.c
new file mode 100755
index 0000000..e5b45d9
--- /dev/null
+++ b/src/accounting-iptables.c
@@ -0,0 +1,367 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
+ *
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <xtables.h>
+#include <inttypes.h>
+#include <setjmp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+#include "connman.h"
+#include "src/shared/util.h"
+
+#define CHAIN_PREFIX "connman-"
+#define INGRESS_IP_ACC (CHAIN_PREFIX"INGRESS_IP_ACC")
+#define EGRESS_IP_ACC (CHAIN_PREFIX"EGRESS_IP_ACC")
+
+struct iptables_entry {
+ int type;
+ unsigned int offset;
+ int builtin;
+ int counter_idx;
+ struct ipt_entry *entry;
+ struct ip6t_entry *entry6;
+};
+
+static int get_ingress_ip_acc_info(int type, const char *table_name, const
char *chain, struct ip_accounting_info *ip_acc)
+{
+ GList *chain_head, *chain_tail, *list, *next;
+ char src_ip_addrs[INET_ADDRSTRLEN], dst_ip_addrs[INET_ADDRSTRLEN];
+ struct iptables_entry *entry;
+ int err = 0;
+
+ DBG("%d -t %s -L %s", type, table_name, chain);
+
+ err = __connman_iptables_get_chain(type, table_name, chain, &chain_head,
&chain_tail);
+
+ if (err < 0) {
+ return err;
+ }
+
+ list = chain_head;
+
+ // if no entry
+ if (list == chain_tail->prev) {
+ DBG("No entries found for this %s chain", chain);
+ return 0;
+ }
+
+ // traversing through the entries
+ while (list != chain_tail->prev) {
+ entry = list->data;
+ next = g_list_next(list);
+ // check for IPv4 Entries
+ if (entry->type == AF_INET) {
+ if (inet_ntop(entry->type, &entry->entry->ip.src, &src_ip_addrs,
INET_ADDRSTRLEN) == NULL) {
+ DBG("Invalid ipv4 source address");
+ return -EINVAL;
+ }
+ if (inet_ntop(entry->type, &entry->entry->ip.dst, &dst_ip_addrs,
INET_ADDRSTRLEN) == NULL) {
+ DBG("Invalid ipv4 destination address");
+ return -EINVAL;
+ }
+ DBG("src %s dst %s packets %"PRIu64" ""bytes %"PRIu64, src_ip_addrs,
dst_ip_addrs
+ , (uint64_t)entry->entry->counters.pcnt,
(uint64_t)entry->entry->counters.bcnt);
+
+ if (!strcmp(src_ip_addrs, ip_acc->ipv4_address)) {
+ ip_acc->ingress.pcnt = entry->entry->counters.pcnt;
+ ip_acc->ingress.bcnt = entry->entry->counters.bcnt;
+ break;
+ }
+
+ }
+ list = next;
+ }
+ return 0;
+}
+
+static int get_egress_ip_acc_info(int type, const char *table_name, const
char *chain, struct ip_accounting_info *ip_acc)
+{
+ GList *chain_head, *chain_tail, *list, *next;
+ char src_ip_addrs[INET_ADDRSTRLEN], dst_ip_addrs[INET_ADDRSTRLEN];
+ struct iptables_entry *entry;
+ int err = 0;
+
+ DBG("%d -t %s -L %s", type, table_name, chain);
+
+ err = __connman_iptables_get_chain(type, table_name, chain, &chain_head,
&chain_tail);
+
+ if (err < 0) {
+ return err;
+ }
+
+ list = chain_head;
+
+ // if no entry
+ if (list == chain_tail->prev) {
+ DBG("No entries found for this %s chain", chain);
+ return 0;
+ }
+
+ // traversing through the entries
+ while (list != chain_tail->prev) {
+ entry = list->data;
+ next = g_list_next(list);
+ // check for IPv4 Entries
+ if (entry->type == AF_INET) {
+ if (inet_ntop(entry->type, &entry->entry->ip.src, &src_ip_addrs,
INET_ADDRSTRLEN) == NULL) {
+ DBG("Invalid ipv4 source address");
+ return -EINVAL;
+ }
+ if (inet_ntop(entry->type, &entry->entry->ip.dst, &dst_ip_addrs,
INET_ADDRSTRLEN) == NULL) {
+ DBG("Invalid ipv4 destination address");
+ return -EINVAL;
+ }
+ DBG("src %s dst %s packets %"PRIu64" ""bytes %"PRIu64, src_ip_addrs,
dst_ip_addrs
+ , (uint64_t)entry->entry->counters.pcnt,
(uint64_t)entry->entry->counters.bcnt);
+
+ if (!strcmp(dst_ip_addrs, ip_acc->ipv4_address)) {
+ ip_acc->egress.pcnt = entry->entry->counters.pcnt;
+ ip_acc->egress.bcnt = entry->entry->counters.bcnt;
+ break;
+ }
+
+ }
+ list = next;
+ }
+
+ return 0;
+}
+
+int __connman_get_ip_acc_info(struct ip_accounting_info *ip_acc)
+{
+ char *user_defined_chain;
+ int err = 0;
+
+ // get ip accounting for ingress packets
+ DBG("get ip accounting ingress info for ipv4 address (%s)",
ip_acc->ipv4_address);
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ err = get_ingress_ip_acc_info(2, "filter", user_defined_chain, ip_acc);
+ if (err < 0) {
+ DBG("failed to get ip accounting from ingress chain %s, error:(%d/%s)",
user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+
+ // get ip accounting for egress packets
+ DBG("get ip accounting egress info for ipv4 address (%s)",
ip_acc->ipv4_address);
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ err = get_egress_ip_acc_info(2, "filter", user_defined_chain, ip_acc);
+ if (err < 0) {
+ DBG("failed to get ip accounting from egress chain %s, error:(%d/%s)",
user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+
+ return err;
+}
+
+int __connman_add_ip_acc_rules(char *ip_addrs)
+{
+ char *user_defined_chain = NULL;
+ char *user_defined_rule = NULL;
+ int err = 0;
+
+ // Adding the ingress ip accounting rules
+ DBG("adding ip accounting ingress rules for ipv4 address (%s)", ip_addrs);
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ user_defined_rule = g_strdup_printf("-s %s", ip_addrs);
+ err = __connman_iptables_append(AF_INET, "filter", user_defined_chain,
user_defined_rule);
+ if (err < 0) {
+ DBG("failed to add %s rule in chain %s, error:(%d/%s)",
user_defined_rule, user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_rule);
+
+ // Adding the egress ip accounting rules
+ DBG("adding ip accounting egress rules for ipv4 address (%s)", ip_addrs);
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ user_defined_rule = g_strdup_printf("-d %s", ip_addrs);
+ err = __connman_iptables_append(AF_INET, "filter", user_defined_chain,
user_defined_rule);
+ if (err < 0) {
+ DBG("failed to add %s rule in chain %s, error:(%d/%s)",
user_defined_rule, user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_rule);
+
+ //committing the rules to kernel
+ DBG("commit ip accounting changes");
+ err = __connman_iptables_commit(AF_INET, "filter");
+ if (err < 0) {
+ DBG("failed to commit filter rule in chain, error:(%d/%s)", -err,
strerror(-err));
+ }
+
+ return err;
+}
+
+int __connman_delete_ip_acc_rules(char *ip_addrs)
+{
+ char *user_defined_chain = NULL;
+ char *user_defined_rule = NULL;
+ int err = 0;
+
+ // Deleting the ingress ip accounting rules
+ DBG("deleting ip accounting ingress rules for ipv4 address (%s)",
ip_addrs);
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ user_defined_rule = g_strdup_printf("-s %s/32 -j ACCEPT", ip_addrs);
+ err = __connman_iptables_delete(AF_INET, "filter", user_defined_chain,
user_defined_rule);
+ if (err < 0) {
+ DBG("failed to delete %s rule in chain %s, error:(%d/%s)",
user_defined_rule, user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_rule);
+
+ //Deleting the egress ip accounting rules
+ DBG("deleting ip accounting egress rules for ipv4 address (%s)",
ip_addrs);
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ user_defined_rule = g_strdup_printf("-d %s/32 -j ACCEPT", ip_addrs);
+ err = __connman_iptables_delete(AF_INET, "filter", user_defined_chain,
user_defined_rule);
+ if (err < 0) {
+ DBG("failed to delete %s rule in chain %s, error:(%d/%s)",
user_defined_rule, user_defined_chain, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_rule);
+
+ //committing the rules to kernel
+ DBG("commit ip accounting changes");
+ err = __connman_iptables_commit(AF_INET, "filter");
+ if (err < 0) {
+ DBG("failed to commit filter rule in chain, error:(%d/%s)", -err,
strerror(-err));
+ }
+
+ return err;
+}
+
+int __connman_create_ip_acc_chain(char *ifname)
+{
+ char *user_defined_chain = NULL;
+ char *user_defined_entry = NULL;
+ int err = 0;
+
+ // creating user defined chain for ingress ip accounting
+ DBG("creating ip accounting chain for ingress");
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ err = __connman_iptables_new_chain(AF_INET, "filter", user_defined_chain);
+ if (err < 0) {
+ DBG("failed to create new chain -t filter %s, error:(%d/%s)",
user_defined_chain, -err, strerror(-err));
+ }
+ user_defined_entry = g_strdup_printf("-i %s -j %s", ifname,
user_defined_chain);
+ err = __connman_iptables_insert(AF_INET, "filter", "FORWARD",
user_defined_entry);
+ if (err < 0) {
+ DBG("failed to insert entry -t filter %s, error:(%d/%s)",
user_defined_entry, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_entry);
+
+ // creating user defined chain for egress ip accounting
+ DBG("creating ip accounting chain for egress");
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ err = __connman_iptables_new_chain(AF_INET, "filter", user_defined_chain);
+ if (err < 0) {
+ DBG("failed to create new chain -t filter %s, error:(%d/%s)",
user_defined_chain, -err, strerror(-err));
+ }
+ user_defined_entry = g_strdup_printf("-o %s -j %s", ifname,
user_defined_chain);
+ err = __connman_iptables_insert(AF_INET, "filter", "FORWARD",
user_defined_entry);
+ if (err < 0) {
+ DBG("failed to insert entry -t filter %s, error:(%d/%s)",
user_defined_entry, -err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_entry);
+
+ //committing the ip accounting chain to kernel
+ DBG("commit ip accounting changes");
+ err = __connman_iptables_commit(AF_INET, "filter");
+ if (err < 0) {
+ DBG("failed to commit filter rule in chain, error:(%d/%s)", -err,
strerror(-err));
+ }
+ return err;
+}
+
+int __connman_destroy_ip_acc_chain(char *ifname)
+{
+ char *user_defined_chain = NULL;
+ char *user_defined_entry = NULL;
+ int err = 0;
+
+ // Deleting user defined chain for ingress ip accounting
+ DBG("deleting ip accounting rules for ingress");
+ user_defined_chain = g_strdup_printf("%s", INGRESS_IP_ACC);
+ user_defined_entry = g_strdup_printf("-i %s -j %s", ifname,
user_defined_chain);
+ // Delete rule, if any
+ err = __connman_iptables_delete(AF_INET, "filter", "FORWARD",
user_defined_entry);
+ if (err < 0) {
+ DBG("failed to delete -D FORWARD %s, error:(%d/%s)", user_defined_entry,
-err, strerror(-err));
+ }
+ // Flush rules, if any
+ DBG("flush ip accounting chain for ingress");
+ err = __connman_iptables_flush_chain(AF_INET, "filter",
user_defined_chain);
+ if (err < 0) {
+ DBG("failed to flush chain -F %s, error:(%d/%s)", user_defined_chain,
-err, strerror(-err));
+ }
+ // Delete the chain
+ DBG("deleting ip accounting chain for ingress");
+ err = __connman_iptables_delete_chain(AF_INET, "filter",
user_defined_chain);
+ if (err < 0) {
+ DBG("failed to delete chain -X %s, error:(%d/%s)", user_defined_chain,
-err, strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_entry);
+
+ // Deleting user defined chain for egress ip accounting
+ DBG("deleting ip accounting rules for egress");
+ user_defined_chain = g_strdup_printf("%s", EGRESS_IP_ACC);
+ user_defined_entry = g_strdup_printf("-o %s -j %s", ifname,
user_defined_chain);
+ // Delete rule, if any
+ err = __connman_iptables_delete(AF_INET, "filter", "FORWARD",
user_defined_entry);
+ if (err < 0) {
+ DBG("failed to delete -D FORWARD %s, error:(%d/%s)", user_defined_entry,
-err, strerror(-err));
+ }
+ // Flush rules, if any
+ DBG("flush ip accounting chain for egress");
+ err = __connman_iptables_flush_chain(AF_INET, "filter",
user_defined_chain);
+ if (err < 0) {
+ DBG("failed to flush chain -F %s, error:(%d/%s)", user_defined_chain,
-err, strerror(-err));
+ }
+ // Delete the chain
+ DBG("deleting ip accounting chain for egress");
+ err = __connman_iptables_delete_chain(AF_INET, "filter",
user_defined_chain);
+ if (err < 0) {
+ DBG("Failed to delete chain -X %s: %s", user_defined_chain,
strerror(-err));
+ }
+ g_free(user_defined_chain);
+ g_free(user_defined_entry);
+
+ //committing the rules to kernel
+ DBG("commit ip accounting changes");
+ err = __connman_iptables_commit(AF_INET, "filter");
+ if (err < 0) {
+ DBG("failed to commit filter rule in chain, error:(%d/%s)", -err,
strerror(-err));
+ }
+
+ return err;
+}
diff --git a/src/connman.h b/src/connman.h
old mode 100644
new mode 100755
index 3bdc0dc..3530937
--- a/src/connman.h
+++ b/src/connman.h
@@ -951,6 +951,11 @@ int __connman_iptables_delete(int type,
const char *table_name,
const char *chain,
const char *rule_spec);
+int __connman_iptables_get_chain(int type,
+ const char *table_name,
+ const char *chain,
+ GList **chain_head,
+ GList **chain_tail);
typedef void (*connman_iptables_iterate_chains_cb_t) (const char
*chain_name,
void *user_data);
@@ -1015,6 +1020,8 @@ int __connman_nat_enable(const char *name, const char
*address,
unsigned char prefixlen);
void __connman_nat_disable(const char *name);
+#include <connman/accounting-iptables.h>
+
struct firewall_context;
struct firewall_context *__connman_firewall_create(void);
diff --git a/src/iptables.c b/src/iptables.c
old mode 100644
new mode 100755
index 47ea1c2..f4e0e74
--- a/src/iptables.c
+++ b/src/iptables.c
@@ -3646,6 +3646,48 @@ int __connman_iptables_dump(int type, const char
*table_name)
return 0;
}
+int __connman_iptables_get_chain(int type,
+ const char *table_name,
+ const char *chain,
+ GList **chain_head,
+ GList **chain_tail)
+{
+ GList *list, *next;
+ struct connman_iptables_entry *entry;
+ struct connman_iptables *table = NULL;
+ int builtin;
+
+ table = iptables_init(type, table_name);
+
+ if (!table)
+ return -EINVAL;
+
+ DBG("table %s chain %s", table->name, chain);
+
+ // finding the chain head
+ *chain_head = find_chain_head(table, chain);
+ if (!*chain_head)
+ return -EINVAL;
+
+ // finding the chain tail
+ *chain_tail = find_chain_tail(table, chain);
+ if (!*chain_tail)
+ return -EINVAL;
+
+ entry = (*chain_head)->data;
+ builtin = entry->builtin;
+
+ //if it builtin chain then interate starts from head
+ if (builtin >= 0)
+ list = *chain_head;
+ else
+ list = (*chain_head)->next;
+
+ *chain_head = list;
+
+ return 0;
+}
+
int __connman_iptables_new_chain(int type,
const char *table_name,
const char *chain)
diff --git a/src/manager.c b/src/manager.c
old mode 100644
new mode 100755
index 3bf8f4e..0e1bc7e
--- a/src/manager.c
+++ b/src/manager.c
@@ -227,8 +227,13 @@ static DBusMessage
*get_tethering_clients(DBusConnection *conn,
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING, &array);
-
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING, &array);
__connman_tethering_list_clients(&array);
dbus_message_iter_close_container(&iter, &array);
diff --git a/src/tethering.c b/src/tethering.c
old mode 100644
new mode 100755
index e2687b6..e80d4c3
--- a/src/tethering.c
+++ b/src/tethering.c
@@ -50,6 +50,8 @@
#define BRIDGE_NAME "tether"
+#define IP_NOT_OFFERED ("not offered")
+
#define DEFAULT_MTU 1500
static char *private_network_primary_dns = NULL;
@@ -61,7 +63,7 @@ static struct connman_ippool *dhcp_ippool = NULL;
static DBusConnection *connection;
static GHashTable *pn_hash;
-static GHashTable *clients_table;
+static GHashTable *added_clients_table, *removed_clients_table;
struct _clients_notify {
int id;
@@ -139,6 +141,64 @@ static void dhcp_server_error(GDHCPServerError error)
}
}
+struct ip_accounting_info *tether_client_create(void)
+{
+ struct ip_accounting_info *tether_client;
+
+ tether_client = g_try_new0(struct ip_accounting_info, 1);
+ if (!tether_client)
+ return NULL;
+
+ tether_client->ipv4_address = g_strdup(IP_NOT_OFFERED);
+ tether_client->ingress.bcnt = 0;
+ tether_client->ingress.bcnt = 0;
+ tether_client->egress.bcnt = 0;
+ tether_client->egress.bcnt = 0;
+ return tether_client;
+}
+
+static void lease_added(unsigned char *mac, uint32_t ipv4)
+{
+ char mac_addr[18];
+ struct in_addr addr;
+ struct ip_accounting_info *teth_cli = NULL;
+
+ snprintf(mac_addr, 18,
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]);
+
+ addr.s_addr = ipv4;
+ char *ip_addr = inet_ntoa(addr);
+
+ DBG("ipv4 address(%s) leased for client mac(%s)", ip_addr, mac_addr);
+
+ if (true == g_hash_table_lookup_extended(added_clients_table,
+ mac_addr,
+ NULL, &teth_cli)) {
+ if (!strcmp(teth_cli->ipv4_address, g_strdup(IP_NOT_OFFERED))) {
+ // ipv4 address is not offered, it new client
+ DBG("new ip address is offered to new client");
+ g_free(teth_cli->ipv4_address);
+ teth_cli->ipv4_address = g_strdup(ip_addr);
+ __connman_add_ip_acc_rules(teth_cli->ipv4_address);
+ } else if (strcmp(teth_cli->ipv4_address, ip_addr)) {
+ // new ipv4 address is assigned, may be lease expired
+ DBG("new ip address is offered to existing client, may be lease expired");
+ __connman_delete_ip_acc_rules(teth_cli->ipv4_address);
+ g_free(teth_cli->ipv4_address);
+ teth_cli->ipv4_address = g_strdup(ip_addr);
+ __connman_add_ip_acc_rules(teth_cli->ipv4_address);
+ } else {
+ // sometime lease_added is called multiple time and ipv4 address is same
+ DBG("already ip address is offered to this client");
+ }
+ } else {
+ // possibly this situation will not happen
+ DBG("client is not authorised/registered, fatal error!");
+ }
+}
+
static GDHCPServer *dhcp_server_start(const char *bridge,
const char *router, const char *subnet,
const char *start_ip, const char *end_ip,
@@ -167,6 +227,7 @@ static GDHCPServer *dhcp_server_start(const char
*bridge,
g_dhcp_server_set_option(dhcp_server, G_DHCP_ROUTER, router);
g_dhcp_server_set_option(dhcp_server, G_DHCP_DNS_SERVER, dns);
g_dhcp_server_set_ip_range(dhcp_server, start_ip, end_ip);
+ g_dhcp_server_set_lease_added_cb(dhcp_server, lease_added);
g_dhcp_server_start(dhcp_server);
@@ -195,9 +256,42 @@ static void unregister_client(gpointer key,
__connman_tethering_client_unregister(addr);
}
+static void tether_client_copy(gpointer key,
+ gpointer value, gpointer user_data)
+{
+ GHashTable *tether_client_table = user_data;
+ struct ip_accounting_info *copy_teth_client;
+ struct ip_accounting_info *tether_client = value;
+
+ copy_teth_client = tether_client_create();
+ if (tether_client) {
+ copy_teth_client->ipv4_address = g_strdup(tether_client->ipv4_address);
+ g_hash_table_insert(tether_client_table, g_strdup(key), copy_teth_client);
+ } else {
+ DBG("could not create tether client entry");
+ }
+}
+
+static void tether_client_destroy(gpointer data)
+{
+ struct ip_accounting_info *tether_client = data;
+
+ g_free(tether_client->ipv4_address);
+ g_free(tether_client);
+}
+
static void unregister_all_clients(void)
{
- g_hash_table_foreach(clients_table, unregister_client, NULL);
+ GHashTable *tether_client_table;
+
+ tether_client_table = g_hash_table_new_full(g_str_hash,
+ g_str_equal,
+ g_free,
+ tether_client_destroy);
+ g_hash_table_foreach(added_clients_table, tether_client_copy,
+ tether_client_table);
+ g_hash_table_foreach(tether_client_table, unregister_client, NULL);
+ g_hash_table_destroy(tether_client_table);
}
int __connman_tethering_set_enabled(void)
@@ -306,6 +400,8 @@ int __connman_tethering_set_enabled(void)
DBG("Cannot setup IPv6 prefix delegation %d/%s", err,
strerror(-err));
+ __connman_create_ip_acc_chain(BRIDGE_NAME);
+
DBG("tethering started");
return 0;
@@ -345,9 +441,60 @@ void __connman_tethering_set_disabled(void)
g_free(private_network_secondary_dns);
private_network_secondary_dns = NULL;
+ __connman_destroy_ip_acc_chain(BRIDGE_NAME);
+
DBG("tethering stopped");
}
+static void append_dict_properties(DBusMessageIter *dict,
+ struct ip_accounting_info *tether_client,
+ char *addr)
+{
+ struct ip_accounting_info *removed_tether_client = NULL;
+
+ connman_dbus_dict_append_basic(dict, "mac", DBUS_TYPE_STRING, &addr);
+
+ connman_dbus_dict_append_basic(dict, "ipv4", DBUS_TYPE_STRING,
+ &tether_client->ipv4_address);
+
+ __connman_get_ip_acc_info(tether_client);
+
+ connman_dbus_dict_append_basic(dict, "tx-bytes", DBUS_TYPE_UINT64,
+ &tether_client->ingress.bcnt);
+
+ connman_dbus_dict_append_basic(dict, "rx-bytes", DBUS_TYPE_UINT64,
+ &tether_client->egress.bcnt);
+
+ removed_tether_client = g_hash_table_lookup(removed_clients_table, addr);
+ if (removed_tether_client) {
+ connman_dbus_dict_append_basic(dict, "previous tx-bytes",
+ DBUS_TYPE_UINT64,
+ &removed_tether_client->ingress.bcnt);
+ connman_dbus_dict_append_basic(dict, "previous rx-bytes",
+ DBUS_TYPE_UINT64,
+ &removed_tether_client->egress.bcnt);
+ } else {
+ DBG("no history found for this client");
+ }
+}
+
+static void append_struct_ip_acc_info(char *addr,
+ struct ip_accounting_info *tether_client,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter entry, dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
+
+ connman_dbus_dict_open(&entry, &dict);
+
+ append_dict_properties(&dict, tether_client, addr);
+
+ connman_dbus_dict_close(&entry, &dict);
+
+ dbus_message_iter_close_container(iter, &entry);
+}
+
static void append_client(gpointer key, gpointer value,
gpointer user_data)
{
@@ -360,7 +507,11 @@ static void append_client(gpointer key, gpointer value,
void __connman_tethering_list_clients(DBusMessageIter *array)
{
- g_hash_table_foreach(clients_table, append_client, array);
+ DBG("found %d clients in hash table",
+ g_hash_table_size(added_clients_table));
+
+ g_hash_table_foreach(added_clients_table, append_struct_ip_acc_info,
+ array);
}
static void setup_tun_interface(unsigned int flags, unsigned change,
@@ -494,7 +645,7 @@ static gboolean client_send_changed(gpointer data)
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING, &array);
- g_hash_table_foreach(clients_table, append_client, &array);
+ g_hash_table_foreach(added_clients_table, append_client, &array);
dbus_message_iter_close_container(&iter, &array);
@@ -631,14 +782,68 @@ int __connman_private_network_release(const char
*path)
void __connman_tethering_client_register(const char *addr)
{
- g_hash_table_insert(clients_table, g_strdup(addr), NULL);
+ struct ip_accounting_info *tether_client;
+
+ DBG("adding %s mac address in hash table", addr);
+
+ tether_client = tether_client_create();
+
+ if (tether_client)
+ g_hash_table_insert(added_clients_table, g_strdup(addr), tether_client);
+ else
+ DBG("could not create tether client entry");
+
+ DBG("hash table size %d", g_hash_table_size(added_clients_table));
+
client_added(addr);
}
void __connman_tethering_client_unregister(const char *addr)
{
- client_removed(addr);
- g_hash_table_remove(clients_table, addr);
+ struct ip_accounting_info *existing_tether_client;
+ struct ip_accounting_info *old_tether_client;
+ struct ip_accounting_info *tether_client;
+
+ DBG("removing %s mac address from hash table", addr);
+
+ existing_tether_client = g_hash_table_lookup(added_clients_table, addr);
+ if (existing_tether_client) {
+ if (strcmp(existing_tether_client->ipv4_address,
+ g_strdup(IP_NOT_OFFERED))) {
+ __connman_get_ip_acc_info(existing_tether_client);
+ __connman_delete_ip_acc_rules(existing_tether_client->ipv4_address);
+ old_tether_client = g_hash_table_lookup(removed_clients_table, addr);
+ if (old_tether_client) {
+ DBG("replacing existing client in hash table");
+ tether_client = tether_client_create();
+ if (tether_client) {
+ tether_client->ingress.bcnt = old_tether_client->ingress.bcnt
+ + existing_tether_client->ingress.bcnt;
+ tether_client->egress.bcnt = old_tether_client->egress.bcnt
+ + existing_tether_client->egress.bcnt;
+ g_hash_table_replace(removed_clients_table,
+ g_strdup(addr),
+ tether_client);
+ } else
+ DBG("could not create tether client entry");
+ } else {
+ DBG("adding client in hash table");
+ tether_client = tether_client_create();
+ if (tether_client) {
+ tether_client->ingress.bcnt = existing_tether_client->ingress.bcnt;
+ tether_client->egress.bcnt = existing_tether_client->egress.bcnt;
+ g_hash_table_insert(removed_clients_table,
+ g_strdup(addr),
+ tether_client);
+ } else
+ DBG("could not create tether client entry");
+ }
+ } else
+ DBG("ip address not offered for %s ", addr);
+ g_hash_table_remove(added_clients_table, addr);
+ client_removed(addr);
+ } else
+ DBG("could not remove client from hash table");
}
int __connman_tethering_init(void)
@@ -654,8 +859,11 @@ int __connman_tethering_init(void)
pn_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, remove_private_network);
- clients_table = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, NULL);
+ added_clients_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, tether_client_destroy);
+
+ removed_clients_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, tether_client_destroy);
clients_notify = g_new0(struct _clients_notify, 1);
clients_notify->remove = g_hash_table_new_full(g_str_hash, g_str_equal,
@@ -685,8 +893,11 @@ void __connman_tethering_cleanup(void)
g_free(clients_notify);
clients_notify = NULL;
- g_hash_table_destroy(clients_table);
- clients_table = NULL;
+ g_hash_table_destroy(added_clients_table);
+ added_clients_table = NULL;
+
+ g_hash_table_destroy(removed_clients_table);
+ removed_clients_table = NULL;
dbus_connection_unref(connection);
}
--
Thanks,
Aravind
--000000000000ff5ca605a69e52b6
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">=C2=A0diff --git a/Makefile.am b/Makefile.am<br>old mode 1=
00644<br>new mode 100755<br>index 5971ca9..44148df<br>--- a/Makefile.am<br>=
+++ b/Makefile.am<br>@@ -12,7 +12,7 @@ include_HEADERS =3D include/log.h in=
clude/plugin.h \<br>=C2=A0 include/storage.h
include/provision.h \<br>=C2=
=A0 include/session.h include/ipaddress.h include/agent.h
\<br>=C2=A0 i=
nclude/inotify.h include/peer.h include/machine.h \<br>-
include/acd.h in=
clude/tethering.h<br>+ include/acd.h include/tethering.h
include/accounti=
ng-iptables.h<br>=C2=A0<br>=C2=A0nodist_include_HEADERS =3D include/version=
.h<br>=C2=A0<br>@@ -152,7 +152,7 @@ src_connmand_wait_online_LDADD =3D gdbu=
s/<a href=3D"http://libgdbus-internal.la">libgdbus-internal.la</a> \<br>=C2=
=A0 @GLIB_LIBS@ @DBUS_LIBS@<br>=C2=A0<br>=C2=A0if
XTABLES<br>-src_connman=
d_SOURCES +=3D src/iptables.c src/firewall-iptables.c<br>+src_connmand_SOUR=
CES +=3D src/iptables.c src/firewall-iptables.c src/accounting-iptables.c<b=
r>=C2=A0src_connmand_LDADD +=3D @XTABLES_LIBS@<br>=C2=A0endif<br>=C2=A0<br>=
diff --git a/include/accounting-iptables.h b/include/accounting-iptables.h<=
br>new file mode 100755<br>index 0000000..3a9cc30<br>--- /dev/null<br>+++ b=
/include/accounting-iptables.h<br>@@ -0,0 +1,49 @@<br>+/*<br>+ *<br>+ * =C2=
=A0Connection Manager<br>+ *<br>+ * =C2=A0Copyright (C) 2007-2013 =C2=A0Int=
el Corporation. All rights reserved.<br>+ *<br>+ * =C2=A0This program is fr=
ee software; you can redistribute it and/or modify<br>+ * =C2=A0it under th=
e terms of the GNU General Public License version 2 as<br>+ * =C2=A0publish=
ed by the Free Software Foundation.<br>+ *<br>+ * =C2=A0This program is dis=
tributed in the hope that it will be useful,<br>+ * =C2=A0but WITHOUT ANY W=
ARRANTY; without even the implied warranty of<br>+ * =C2=A0MERCHANTABILITY =
or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 See the<br>+ * =C2=A0GNU General=
Public License for more details.<br>+ *<br>+ * =C2=A0You should have recei=
ved a copy of the GNU General Public License<br>+ * =C2=A0along with this p=
rogram; if not, write to the Free Software<br>+ * =C2=A0Foundation, Inc., 5=
1 Franklin St, Fifth Floor, Boston, MA =C2=A002110-1301 =C2=A0USA<br>+ *<br=
>+ */<br>+<br>+#ifndef __CONNMAN_ACCOUNTING_IPTABLES_H<br>+#define __CONNMA=
N_ACCOUNTING_IPTABLES_H<br>+<br>+#ifdef __cplusplus<br>+extern "C"=
; {<br>+#endif<br>+<br>+struct counters {<br>+ __u64 pcnt, bcnt; =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 /* Packet and byte counters */<br>+};<br>+<br>+str=
uct ip_accounting_info {<br>+ char *ipv4_address; /* IP address
of the cli=
ent */<br>+ struct counters egress; /* Transmitted bytes
information of th=
e client */<br>+ struct counters ingress; /* Received bytes
information of =
the client */<br>+};<br>+<br>+int __connman_get_ip_acc_info(struct ip_accou=
nting_info *ip_acc);<br>+int __connman_add_ip_acc_rules(char *ip_addrs);<br=
>+int __connman_delete_ip_acc_rules(char *ip_addrs);<br>+int __connman_crea=
te_ip_acc_chain(char *ifname);<br>+int __connman_destroy_ip_acc_chain(char =
*ifname);<br>+<br>+#ifdef __cplusplus<br>+}<br>+#endif<br>+<br>+#endif /* _=
_CONNMAN_ACCOUNTING_IPTABLES_H */<br>diff --git a/src/accounting-iptables.c=
b/src/accounting-iptables.c<br>new file mode 100755<br>index 0000000..e5b4=
5d9<br>--- /dev/null<br>+++ b/src/accounting-iptables.c<br>@@ -0,0 +1,367 @=
@<br>+/*<br>+ *<br>+ * =C2=A0Connection Manager<br>+ *<br>+ * =C2=A0Copyrig=
ht (C) 2007-2013 =C2=A0Intel Corporation. All rights reserved.<br>+ *<br>+ =
* =C2=A0This program is free software; you can redistribute it and/or modif=
y<br>+ * =C2=A0it under the terms of the GNU General Public License version=
2 as<br>+ * =C2=A0published by the Free Software Foundation.<br>+ *<br>+ *=
=C2=A0This program is distributed in the hope that it will be useful,<br>+=
* =C2=A0but WITHOUT ANY WARRANTY; without even the implied warranty of<br>=
+ * =C2=A0MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 See th=
e<br>+ * =C2=A0GNU General Public License for more details.<br>+ *<br>+ * =
=C2=A0You should have received a copy of the GNU General Public License<br>=
+ * =C2=A0along with this program; if not, write to the Free Software<br>+ =
* =C2=A0Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA =C2=A0021=
10-1301 =C2=A0USA<br>+ *<br>+ */<br>+<br>+#include <errno.h><br>+#inc=
lude <getopt.h><br>+#include <stdlib.h><br>+#include <stdio.=
h><br>+#include <string.h><br>+#include <unistd.h><br>+#incl=
ude <errno.h><br>+#include <sys/socket.h><br>+#include <xtab=
les.h><br>+#include <inttypes.h><br>+#include <setjmp.h><br>=
+<br>+#include <linux/netfilter_ipv4/ip_tables.h><br>+#include <li=
nux/netfilter_ipv6/ip6_tables.h><br>+<br>+#include "connman.h"=
<br>+#include "src/shared/util.h"<br>+<br>+#define CHAIN_PREFIX &=
quot;connman-"<br>+#define INGRESS_IP_ACC (CHAIN_PREFIX"INGRESS_I=
P_ACC")<br>+#define EGRESS_IP_ACC (CHAIN_PREFIX"EGRESS_IP_ACC&quo=
t;)<br>+<br>+struct iptables_entry {<br>+ int type;<br>+ unsigned int
offse=
t;<br>+ int builtin;<br>+ int counter_idx;<br>+ struct ipt_entry
*entry;<br=
>+ struct ip6t_entry *entry6;<br>+};<br>+<br>+static int
>get_ingress_ip_acc=
_info(int type, const char *table_name, const char *chain, struct ip_accoun=
ting_info *ip_acc)<br>+{<br>+ GList *chain_head, *chain_tail, *list, *next;=
<br>+ char src_ip_addrs[INET_ADDRSTRLEN], dst_ip_addrs[INET_ADDRSTRLEN];<br=
>+ struct iptables_entry *entry;<br>+ int err =3D 0;<br>+<br>+
>DBG("%d=
-t %s -L %s", type, table_name, chain);<br>+<br>+ err =3D =C2=A0__con=
nman_iptables_get_chain(type, table_name, chain, &chain_head, &chai=
n_tail);<br>+<br>+ if (err < 0) {<br>+ return err;<br>+
}<br>+<br>+ lis=
t =3D chain_head;<br>+<br>+ // if no entry<br>+ if (list =3D=3D
chain_tail-=
>prev) {<br>+ DBG("No entries found for this %s
chain", chain=
);<br>+ return 0;<br>+ }<br>+<br>+ // traversing through the
entries<br>+ =
while (list !=3D chain_tail->prev) {<br>+ entry =3D
list->data;<br>+=
next =3D g_list_next(list);<br>+ // check for
IPv4 Entries<br>+ if (ent=
ry->type =3D=3D AF_INET) {<br>+ if
(inet_ntop(entry->type, &ent=
ry->entry->ip.src, &src_ip_addrs, INET_ADDRSTRLEN) =3D=3D NULL) {=
<br>+ DBG("Invalid ipv4 source
address");<br>+ return -EINV=
AL;<br>+ }<br>+ if
(inet_ntop(entry->type, &entry->entry->=
ip.dst, &dst_ip_addrs, INET_ADDRSTRLEN) =3D=3D NULL) {<br>+
DBG(&quo=
t;Invalid ipv4 destination address");<br>+ return
-EINVAL;<br>+ }=
<br>+ DBG("src %s dst %s packets %"PRIu64"
=C2=A0"&qu=
ot;bytes %"PRIu64, src_ip_addrs, dst_ip_addrs<br>+
, (uint64_t)ent=
ry->entry->counters.pcnt, (uint64_t)entry->entry->counters.bcnt=
);<br>+<br>+ if (!strcmp(src_ip_addrs,
ip_acc->ipv4_address)) {<br>+ =
ip_acc->ingress.pcnt =3D
entry->entry->counters.pcnt;<br>+ ip=
_acc->ingress.bcnt =3D entry->entry->counters.bcnt;<br>+
break;=
<br>+ }<br>+<br>+ }<br>+ list =3D
next;<br>+ }<br>+ return 0;<br>+}<br>=
+<br>+static int get_egress_ip_acc_info(int type, const char *table_name, c=
onst char *chain, struct ip_accounting_info *ip_acc)<br>+{<br>+ GList *chai=
n_head, *chain_tail, *list, *next;<br>+ char src_ip_addrs[INET_ADDRSTRLEN],=
dst_ip_addrs[INET_ADDRSTRLEN];<br>+ struct iptables_entry *entry;<br>+
int=
err =3D 0;<br>+<br>+ DBG("%d -t %s -L %s", type, table_name, cha=
in);<br>+<br>+ err =3D =C2=A0__connman_iptables_get_chain(type, table_name,=
chain, &chain_head, &chain_tail);<br>+<br>+ if (err < 0) {<br>+=
return err;<br>+ }<br>+<br>+ list =3D
chain_head;<br>+<br>+ // if no entr=
y<br>+ if (list =3D=3D chain_tail->prev) {<br>+ DBG("No
entries fo=
und for this %s chain", chain);<br>+ return 0;<br>+
}<br>+<br>+ // tr=
aversing through the entries<br>+ while (list !=3D chain_tail->prev)
{<b=
r>+ entry =3D list->data;<br>+ next =3D
g_list_next(list);<br>+ // ch=
eck for IPv4 Entries<br>+ if (entry->type =3D=3D AF_INET)
{<br>+ if (=
inet_ntop(entry->type, &entry->entry->ip.src, &src_ip_addr=
s, INET_ADDRSTRLEN) =3D=3D NULL) {<br>+
DBG("Invalid ipv4 source ad=
dress");<br>+ return -EINVAL;<br>+
}<br>+ if (inet_ntop(entry-&=
gt;type, &entry->entry->ip.dst, &dst_ip_addrs, INET_ADDRSTRLE=
N) =3D=3D NULL) {<br>+ DBG("Invalid ipv4
destination address")=
;<br>+ return -EINVAL;<br>+ }<br>+
DBG("src %s dst %s packets %=
"PRIu64" =C2=A0""bytes %"PRIu64, src_ip_addrs, dst=
_ip_addrs<br>+ ,
(uint64_t)entry->entry->counters.pcnt, (uint64_t=
)entry->entry->counters.bcnt);<br>+<br>+ if
(!strcmp(dst_ip_addrs, =
ip_acc->ipv4_address)) {<br>+
ip_acc->egress.pcnt =3D entry->en=
try->counters.pcnt;<br>+ ip_acc->egress.bcnt
=3D entry->entry-&=
gt;counters.bcnt;<br>+ break;<br>+
}<br>+<br>+ }<br>+ list =3D next;=
<br>+ }<br>+<br>+ return 0;<br>+}<br>+<br>+int
__connman_get_ip_acc_info(st=
ruct ip_accounting_info *ip_acc)<br>+{<br>+ char *user_defined_chain;<br>+
=
int err =3D 0;<br>+<br>+ // get ip accounting for ingress packets<br>+
DBG(=
"get ip accounting ingress info for ipv4 address (%s)", ip_acc-&g=
t;ipv4_address);<br>+ user_defined_chain =3D g_strdup_printf("%s"=
, INGRESS_IP_ACC);<br>+ err =3D get_ingress_ip_acc_info(2, "filter&quo=
t;, user_defined_chain, ip_acc);<br>+ if (err < 0) {<br>+
DBG("fai=
led to get ip accounting from ingress chain %s, error:(%d/%s)", user_d=
efined_chain, -err, strerror(-err));<br>+ }<br>+
g_free(user_defined_chain)=
;<br>+<br>+ // get ip accounting for egress packets<br>+ DBG("get
ip a=
ccounting egress info for ipv4 address (%s)", ip_acc->ipv4_address)=
;<br>+ user_defined_chain =3D g_strdup_printf("%s", EGRESS_IP_ACC=
);<br>+ err =3D get_egress_ip_acc_info(2, "filter", user_defined_=
chain, ip_acc);<br>+ if (err < 0) {<br>+ DBG("failed to get
ip acc=
ounting from egress chain %s, error:(%d/%s)", user_defined_chain, -err=
, strerror(-err));<br>+ }<br>+ g_free(user_defined_chain);<br>+<br>+ return=
err;<br>+}<br>+<br>+int __connman_add_ip_acc_rules(char *ip_addrs)<br>+{<b=
r>+ char *user_defined_chain =3D NULL;<br>+ char *user_defined_rule =3D NUL=
L;<br>+ int err =3D 0;<br>+<br>+ // Adding the ingress ip accounting
rules<=
br>+ DBG("adding ip accounting ingress rules for ipv4 address (%s)&quo=
t;, ip_addrs);<br>+ user_defined_chain =3D g_strdup_printf("%s", =
INGRESS_IP_ACC);<br>+ user_defined_rule =3D g_strdup_printf("-s %s&quo=
t;, ip_addrs);<br>+ err =3D __connman_iptables_append(AF_INET, "filter=
", user_defined_chain, user_defined_rule);<br>+ if (err < 0) {<br>+=
DBG("failed to add %s rule in chain %s,
error:(%d/%s)", user_de=
fined_rule, user_defined_chain, -err, strerror(-err));<br>+ }<br>+
g_free(u=
ser_defined_chain);<br>+ g_free(user_defined_rule);<br>+<br>+ //
Adding the=
egress ip accounting rules<br>+ DBG("adding ip accounting egress
rule=
s for ipv4 address (%s)", ip_addrs);<br>+ user_defined_chain =3D g_str=
dup_printf("%s", EGRESS_IP_ACC);<br>+ user_defined_rule =3D g_str=
dup_printf("-d %s", ip_addrs);<br>+ err =3D __connman_iptables_ap=
pend(AF_INET, "filter", user_defined_chain, user_defined_rule);<b=
r>+ if (err < 0) {<br>+ DBG("failed to add %s rule in
chain %s, er=
ror:(%d/%s)", user_defined_rule, user_defined_chain, -err, strerror(-e=
rr));<br>+ }<br>+ g_free(user_defined_chain);<br>+
g_free(user_defined_rule=
);<br>+<br>+ //committing the rules to kernel<br>+ DBG("commit ip
acco=
unting changes");<br>+ err =3D __connman_iptables_commit(AF_INET, &quo=
t;filter");<br>+ if (err < 0) {<br>+ DBG("failed to
commit fi=
lter rule in chain, error:(%d/%s)", -err, strerror(-err));<br>+ }<br>+=
<br>+ return err;<br>+}<br>+<br>+int __connman_delete_ip_acc_rules(char *ip=
_addrs)<br>+{<br>+ char *user_defined_chain =3D NULL;<br>+ char
*user_defin=
ed_rule =3D NULL;<br>+ int err =3D 0;<br>+<br>+ // Deleting the ingress
ip =
accounting rules<br>+ DBG("deleting ip accounting ingress rules for ip=
v4 address (%s)", ip_addrs);<br>+ user_defined_chain =3D g_strdup_prin=
tf("%s", INGRESS_IP_ACC);<br>+ user_defined_rule =3D
g_strdup_pri=
ntf("-s %s/32 -j ACCEPT", ip_addrs);<br>+ err =3D __connman_iptab=
les_delete(AF_INET, "filter", user_defined_chain, user_defined_ru=
le);<br>+ if (err < 0) {<br>+ DBG("failed to delete %s
rule in cha=
in %s, error:(%d/%s)", user_defined_rule, user_defined_chain, -err, st=
rerror(-err));<br>+ }<br>+ g_free(user_defined_chain);<br>+
g_free(user_def=
ined_rule);<br>+<br>+ //Deleting the egress ip accounting rules<br>+ DBG(&q=
uot;deleting ip accounting egress rules for ipv4 address (%s)", ip_add=
rs);<br>+ user_defined_chain =3D g_strdup_printf("%s",
EGRESS_IP_=
ACC);<br>+ user_defined_rule =3D g_strdup_printf("-d %s/32 -j
ACCEPT&q=
uot;, ip_addrs);<br>+ err =3D __connman_iptables_delete(AF_INET, "filt=
er", user_defined_chain, user_defined_rule);<br>+ if (err < 0) {<br=
>+ DBG("failed to delete %s rule in chain %s,
>error:(%d/%s)", us=
er_defined_rule, user_defined_chain, -err, strerror(-err));<br>+ }<br>+
g_f=
ree(user_defined_chain);<br>+ g_free(user_defined_rule);<br>+<br>+
//commit=
ting the rules to kernel<br>+ DBG("commit ip accounting changes")=
;<br>+ err =3D __connman_iptables_commit(AF_INET, "filter");<br>+=
if (err < 0) {<br>+ DBG("failed to commit filter rule
in chain, e=
rror:(%d/%s)", -err, strerror(-err));<br>+ }<br>+<br>+ return err;<br>=
+}<br>+<br>+int __connman_create_ip_acc_chain(char *ifname)<br>+{<br>+ char=
*user_defined_chain =3D NULL;<br>+ char *user_defined_entry =3D NULL;<br>+=
int err =3D 0;<br>+<br>+ // creating user defined chain for
ingress ip acc=
ounting<br>+ DBG("creating ip accounting chain for ingress");<br>=
+ user_defined_chain =3D g_strdup_printf("%s",
INGRESS_IP_ACC);<b=
r>+ err =3D __connman_iptables_new_chain(AF_INET, "filter", user_=
defined_chain);<br>+ if (err < 0) {<br>+ DBG("failed to
create new=
chain -t filter %s, error:(%d/%s)", user_defined_chain, -err, strerro=
r(-err));<br>+ }<br>+ user_defined_entry =3D g_strdup_printf("-i %s -j=
%s", ifname, user_defined_chain);<br>+ err =3D __connman_iptables_ins=
ert(AF_INET, "filter", "FORWARD", user_defined_entry);<=
br>+ if (err < 0) {<br>+ DBG("failed to insert entry -t
filter %s,=
error:(%d/%s)", user_defined_entry, -err, strerror(-err));<br>+ }<br>=
+ g_free(user_defined_chain);<br>+
g_free(user_defined_entry);<br>+<br>+ //=
creating user defined chain for egress ip accounting<br>+
DBG("creati=
ng ip accounting chain for egress");<br>+ user_defined_chain =3D g_str=
dup_printf("%s", EGRESS_IP_ACC);<br>+ err =3D __connman_iptables_=
new_chain(AF_INET, "filter", user_defined_chain);<br>+ if (err
&l=
t; 0) {<br>+ DBG("failed to create new chain -t filter %s,
error:(%d/=
%s)", user_defined_chain, -err, strerror(-err));<br>+ }<br>+
user_defi=
ned_entry =3D g_strdup_printf("-o %s -j %s", ifname, user_defined=
_chain);<br>+ err =3D __connman_iptables_insert(AF_INET, "filter"=
, "FORWARD", user_defined_entry);<br>+ if (err < 0) {<br>+
DB=
G("failed to insert entry -t filter %s, error:(%d/%s)", user_defi=
ned_entry, -err, strerror(-err));<br>+ }<br>+ g_free(user_defined_chain);<b=
r>+ g_free(user_defined_entry);<br>+<br>+ //committing the ip accounting
ch=
ain to kernel<br>+ DBG("commit ip accounting changes");<br>+
err =
=3D __connman_iptables_commit(AF_INET, "filter");<br>+ if (err
&l=
t; 0) {<br>+ DBG("failed to commit filter rule in chain,
error:(%d/%s=
)", -err, strerror(-err));<br>+ }<br>+ return err;<br>+}<br>+<br>+int =
__connman_destroy_ip_acc_chain(char *ifname)<br>+{<br>+ char *user_defined_=
chain =3D NULL;<br>+ char *user_defined_entry =3D NULL;<br>+ int err =3D 0;=
<br>+<br>+ // Deleting user defined chain for ingress ip accounting<br>+
DB=
G("deleting ip accounting rules for ingress");<br>+ user_defined_=
chain =3D g_strdup_printf("%s", INGRESS_IP_ACC);<br>+ user_define=
d_entry =3D g_strdup_printf("-i %s -j %s", ifname, user_defined_c=
hain);<br>+ // Delete rule, if any<br>+ err =3D
__connman_iptables_delete(A=
F_INET, "filter", "FORWARD", user_defined_entry);<br>+
=
if (err < 0) {<br>+ DBG("failed to delete -D FORWARD =C2=A0%s,
err=
or:(%d/%s)", user_defined_entry, -err, strerror(-err));<br>+ }<br>+
//=
Flush rules, if any<br>+ DBG("flush ip accounting chain for
ingress&q=
uot;);<br>+ err =3D __connman_iptables_flush_chain(AF_INET, "filter&qu=
ot;, user_defined_chain);<br>+ if (err < 0) {<br>+
DBG("failed to =
flush chain -F %s, error:(%d/%s)", user_defined_chain, -err, strerror(=
-err));<br>+ }<br>+ // Delete the chain<br>+ DBG("deleting ip
accounti=
ng chain for ingress");<br>+ err =3D
__connman_iptables_delete_chain(A=
F_INET, "filter", user_defined_chain);<br>+ if (err < 0) {<br>=
+ DBG("failed to delete chain -X %s, error:(%d/%s)",
user_define=
d_chain, -err, strerror(-err));<br>+ }<br>+ g_free(user_defined_chain);<br>=
+ g_free(user_defined_entry);<br>+<br>+ // Deleting user defined chain
for =
egress ip accounting<br>+ DBG("deleting ip accounting rules for
egress=
");<br>+ user_defined_chain =3D g_strdup_printf("%s", EGRESS=
_IP_ACC);<br>+ user_defined_entry =3D g_strdup_printf("-o %s -j %s&quo=
t;, ifname, user_defined_chain);<br>+ // Delete rule, if any<br>+ err =3D
_=
_connman_iptables_delete(AF_INET, "filter", "FORWARD", =
user_defined_entry);<br>+ if (err < 0) {<br>+
DBG("failed to delet=
e -D FORWARD =C2=A0%s, error:(%d/%s)", user_defined_entry, -err, strer=
ror(-err));<br>+ }<br>+ // Flush rules, if any<br>+ DBG("flush
ip acco=
unting chain for egress");<br>+ err =3D __connman_iptables_flush_chain=
(AF_INET, "filter", user_defined_chain);<br>+ if (err < 0) {<b=
r>+ DBG("failed to flush chain -F %s, error:(%d/%s)",
user_defin=
ed_chain, -err, strerror(-err));<br>+ }<br>+ // Delete the chain<br>+
DBG(&=
quot;deleting ip accounting chain for egress");<br>+ err =3D
__connman=
_iptables_delete_chain(AF_INET, "filter", user_defined_chain);<br=
>+ if (err < 0) {<br>+ DBG("Failed to delete chain -X %s:
>%s"=
, user_defined_chain, strerror(-err));<br>+ }<br>+
g_free(user_defined_chai=
n);<br>+ g_free(user_defined_entry);<br>+<br>+ //committing the rules
to ke=
rnel<br>+ DBG("commit ip accounting changes");<br>+ err =3D
__con=
nman_iptables_commit(AF_INET, "filter");<br>+ if (err < 0) {<b=
r>+ DBG("failed to commit filter rule in chain,
error:(%d/%s)", =
-err, strerror(-err));<br>+ }<br>+<br>+ return err;<br>+}<br>diff --git
a/s=
rc/connman.h b/src/connman.h<br>old mode 100644<br>new mode 100755<br>index=
3bdc0dc..3530937<br>--- a/src/connman.h<br>+++ b/src/connman.h<br>@@ -951,=
6 +951,11 @@ int __connman_iptables_delete(int type,<br>=C2=A0
const cha=
r *table_name,<br>=C2=A0 const char
*chain,<br>=C2=A0 const char *rul=
e_spec);<br>+int __connman_iptables_get_chain(int type,<br>+
const cha=
r *table_name,<br>+ const char
*chain,<br>+ GList **chain_head,<b=
r>+ GList
**chain_tail);<br>=C2=A0<br>=C2=A0typedef void (*connman_ipt=
ables_iterate_chains_cb_t) (const char *chain_name,<br>=C2=A0
void *u=
ser_data);<br>@@ -1015,6 +1020,8 @@ int __connman_nat_enable(const char *na=
me, const char *address,<br>=C2=A0 unsigned char
prefixlen);<br>=C2=A0vo=
id __connman_nat_disable(const char *name);<br>=C2=A0<br>+#include <conn=
man/accounting-iptables.h><br>+<br>=C2=A0struct firewall_context;<br>=C2=
=A0<br>=C2=A0struct firewall_context *__connman_firewall_create(void);<br>d=
iff --git a/src/iptables.c b/src/iptables.c<br>old mode 100644<br>new mode =
100755<br>index 47ea1c2..f4e0e74<br>--- a/src/iptables.c<br>+++ b/src/iptab=
les.c<br>@@ -3646,6 +3646,48 @@ int __connman_iptables_dump(int type, const=
char *table_name)<br>=C2=A0 return 0;<br>=C2=A0}<br>=C2=A0<br>+int __connm=
an_iptables_get_chain(int type,<br>+
const char *table_name,<br>+ =
const char *chain,<br>+
GList **chain_head,<br>+
GList *=
*chain_tail)<br>+{<br>+ GList *list, *next;<br>+ struct
connman_iptables_en=
try *entry;<br>+ struct connman_iptables *table =3D NULL;<br>+ int
builtin;=
<br>+<br>+ table =3D iptables_init(type, table_name);<br>+<br>+ if
(!table)=
<br>+ return -EINVAL;<br>+<br>+ DBG("table %s chain
%s", table-&=
gt;name, chain);<br>+<br>+ // finding the chain head<br>+ *chain_head =3D
f=
ind_chain_head(table, chain);<br>+ if (!*chain_head)<br>+ return
-EINVAL;<=
br>+<br>+ // finding the chain tail<br>+ *chain_tail =3D
find_chain_tail(ta=
ble, chain);<br>+ if (!*chain_tail)<br>+ return
-EINVAL;<br>+<br>+ entry =
=3D (*chain_head)->data;<br>+ builtin =3D
entry->builtin;<br>+<br>+ /=
/if it builtin chain then interate starts from head<br>+ if (builtin
>=
=3D 0)<br>+ list =3D *chain_head;<br>+ else<br>+
list =3D (*chain_head)-&=
gt;next;<br>+<br>+ *chain_head =3D list;<br>+<br>+ return
0;<br>+}<br>+<br>=
=C2=A0int __connman_iptables_new_chain(int type,<br>=C2=A0
const char *=
table_name,<br>=C2=A0 const char
*chain)<br>diff --git a/src/manager.c =
b/src/manager.c<br>old mode 100644<br>new mode 100755<br>index 3bf8f4e..0e1=
bc7e<br>--- a/src/manager.c<br>+++ b/src/manager.c<br>@@ -227,8 +227,13 @@ =
static DBusMessage *get_tethering_clients(DBusConnection *conn,<br>=C2=A0
d=
bus_message_iter_init_append(reply, &iter);<br>=C2=A0<br>=C2=A0 dbus_me=
ssage_iter_open_container(&iter, DBUS_TYPE_ARRAY,<br>-
DBUS_TYPE_STR=
ING_AS_STRING, &array);<br>-<br>+
DBUS_STRUCT_BEGIN_CHAR_AS_STRING<br=
>+ DBUS_TYPE_ARRAY_AS_STRING<br>+
>DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING=
<br>+ DBUS_TYPE_STRING_AS_STRING<br>+
DBUS_TYPE_VARIANT_AS_STRING<b=
r>+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING<br>+
DBUS_STRUCT_END_CHAR_AS_ST=
RING, &array);<br>=C2=A0 __connman_tethering_list_clients(&array);<=
br>=C2=A0<br>=C2=A0 dbus_message_iter_close_container(&iter, &array=
);<br>diff --git a/src/tethering.c b/src/tethering.c<br>old mode 100644<br>=
new mode 100755<br>index e2687b6..e80d4c3<br>--- a/src/tethering.c<br>+++ b=
/src/tethering.c<br>@@ -50,6 +50,8 @@<br>=C2=A0<br>=C2=A0#define BRIDGE_NAM=
E "tether"<br>=C2=A0<br>+#define IP_NOT_OFFERED ("not offere=
d")<br>+<br>=C2=A0#define DEFAULT_MTU 1500<br>=C2=A0<br>=C2=A0static
c=
har *private_network_primary_dns =3D NULL;<br>@@ -61,7 +63,7 @@ static stru=
ct connman_ippool *dhcp_ippool =3D NULL;<br>=C2=A0static DBusConnection *co=
nnection;<br>=C2=A0static GHashTable *pn_hash;<br>=C2=A0<br>-static GHashTa=
ble *clients_table;<br>+static GHashTable *added_clients_table, *removed_cl=
ients_table;<br>=C2=A0<br>=C2=A0struct _clients_notify {<br>=C2=A0 int
id;<=
br>@@ -139,6 +141,64 @@ static void dhcp_server_error(GDHCPServerError erro=
r)<br>=C2=A0 }<br>=C2=A0}<br>=C2=A0<br>+struct ip_accounting_info *tether_c=
lient_create(void)<br>+{<br>+ struct ip_accounting_info *tether_client;<br>=
+<br>+ tether_client =3D g_try_new0(struct ip_accounting_info, 1);<br>+
if =
(!tether_client)<br>+ return NULL;<br>+<br>+
tether_client->ipv4_addres=
s =3D g_strdup(IP_NOT_OFFERED);<br>+ tether_client->ingress.bcnt =3D 0;<=
br>+ tether_client->ingress.bcnt =3D 0;<br>+
tether_client->egress.bc=
nt =3D 0;<br>+ tether_client->egress.bcnt =3D 0;<br>+ return
tether_clie=
nt;<br>+}<br>+<br>+static void lease_added(unsigned char *mac, uint32_t ipv=
4)<br>+{<br>+ char mac_addr[18];<br>+ struct in_addr addr;<br>+ struct
ip_a=
ccounting_info *teth_cli =3D NULL;<br>+<br>+ snprintf(mac_addr, 18,<br>+
=
"%02x:%02x:%02x:%02x:%02x:%02x",<br>+ mac[0], mac[1],
mac[2],<b=
r>+ mac[3], mac[4], mac[5]);<br>+<br>+ addr.s_addr =3D
ipv4;<br>+ char *i=
p_addr =3D inet_ntoa(addr);<br>+<br>+ DBG("ipv4 address(%s) leased for=
client mac(%s)", ip_addr, mac_addr);<br>+<br>+ if (true =3D=3D g_hash=
_table_lookup_extended(added_clients_table,<br>+
mac_addr,<br>+
=
NULL,
&teth_cli)) {<br>+ if (!strcmp(teth_cli->ipv4_addres=
s, g_strdup(IP_NOT_OFFERED))) {<br>+ // ipv4 address is not
offered, it n=
ew client<br>+ DBG("new ip address is offered to new
client");<=
br>+ g_free(teth_cli->ipv4_address);<br>+
teth_cli->ipv4_address =
=3D g_strdup(ip_addr);<br>+
__connman_add_ip_acc_rules(teth_cli->ipv4_=
address);<br>+ } else if (strcmp(teth_cli->ipv4_address, ip_addr))
{<br=
>+ // new ipv4 address is assigned, may be lease
>expired<br>+ DBG("=
;new ip address is offered to existing client, may be lease expired");=
<br>+
__connman_delete_ip_acc_rules(teth_cli->ipv4_address);<br>+
g_=
free(teth_cli->ipv4_address);<br>+
teth_cli->ipv4_address =3D g_str=
dup(ip_addr);<br>+
__connman_add_ip_acc_rules(teth_cli->ipv4_address);=
<br>+ } else {<br>+ // sometime lease_added is
called multiple time and =
ipv4 address is same<br>+ DBG("already ip address is
offered to this=
client");<br>+ }<br>+ } else {<br>+ // possibly
this situation will=
not happen<br>+ DBG("client is not authorised/registered,
fatal erro=
r!");<br>+ }<br>+}<br>+<br>=C2=A0static GDHCPServer *dhcp_server_start=
(const char *bridge,<br>=C2=A0 const char *router,
const char *subnet,<b=
r>=C2=A0 const char *start_ip, const char
*end_ip,<br>@@ -167,6 +227,7 @=
@ static GDHCPServer *dhcp_server_start(const char *bridge,<br>=C2=A0 g_dhc=
p_server_set_option(dhcp_server, G_DHCP_ROUTER, router);<br>=C2=A0
g_dhcp_s=
erver_set_option(dhcp_server, G_DHCP_DNS_SERVER, dns);<br>=C2=A0
g_dhcp_ser=
ver_set_ip_range(dhcp_server, start_ip, end_ip);<br>+ g_dhcp_server_set_lea=
se_added_cb(dhcp_server, lease_added);<br>=C2=A0<br>=C2=A0
g_dhcp_server_st=
art(dhcp_server);<br>=C2=A0<br>@@ -195,9 +256,42 @@ static void unregister_=
client(gpointer key,<br>=C2=A0 __connman_tethering_client_unregister(addr);=
<br>=C2=A0}<br>=C2=A0<br>+static void tether_client_copy(gpointer key,<br>+=
gpointer value, gpointer
user_data)<br>+{<br>+ GHashTable *tether_clie=
nt_table =3D user_data;<br>+ struct ip_accounting_info *copy_teth_client;<b=
r>+ struct ip_accounting_info *tether_client =3D value;<br>+<br>+
copy_teth=
_client =3D tether_client_create();<br>+ if (tether_client) {<br>+
copy_te=
th_client->ipv4_address =3D g_strdup(tether_client->ipv4_address);<br=
>+ g_hash_table_insert(tether_client_table, g_strdup(key),
>copy_teth_clien=
t);<br>+ } else {<br>+ DBG("could not create tether
client entry"=
;);<br>+ }<br>+}<br>+<br>+static void tether_client_destroy(gpointer
data)<=
br>+{<br>+ struct ip_accounting_info *tether_client =3D data;<br>+<br>+
g_f=
ree(tether_client->ipv4_address);<br>+
g_free(tether_client);<br>+}<br>+=
<br>=C2=A0static void unregister_all_clients(void)<br>=C2=A0{<br>-
g_hash_t=
able_foreach(clients_table, unregister_client, NULL);<br>+ GHashTable
*teth=
er_client_table;<br>+<br>+ tether_client_table =3D
g_hash_table_new_full(g_=
str_hash,<br>+
g_str_equal,<br>+
g_free,<br>+
=
tether_client_destroy);<br>+
g_hash_table_foreach(added_clients_table, =
tether_client_copy,<br>+
=C2=A0tether_client_table);<br>+ g_hash=
_table_foreach(tether_client_table, unregister_client, NULL);<br>+
g_hash_t=
able_destroy(tether_client_table);<br>=C2=A0}<br>=C2=A0<br>=C2=A0int __conn=
man_tethering_set_enabled(void)<br>@@ -306,6 +400,8 @@ int __connman_tether=
ing_set_enabled(void)<br>=C2=A0 DBG("Cannot setup IPv6 prefix
delegat=
ion %d/%s", err,<br>=C2=A0 strerror(-err));<br>=C2=A0<br>+
__connman=
_create_ip_acc_chain(BRIDGE_NAME);<br>+<br>=C2=A0 DBG("tethering
start=
ed");<br>=C2=A0<br>=C2=A0 return 0;<br>@@ -345,9 +441,60 @@ void __con=
nman_tethering_set_disabled(void)<br>=C2=A0 g_free(private_network_secondar=
y_dns);<br>=C2=A0 private_network_secondary_dns =3D NULL;<br>=C2=A0<br>+
__=
connman_destroy_ip_acc_chain(BRIDGE_NAME);<br>+<br>=C2=A0
DBG("tetheri=
ng stopped");<br>=C2=A0}<br>=C2=A0<br>+static void append_dict_propert=
ies(DBusMessageIter *dict,<br>+
=C2=A0 struct ip_accounting_info *t=
ether_client,<br>+
=C2=A0 char *addr)<br>+{<br>+ struct ip_accounti=
ng_info *removed_tether_client =3D NULL;<br>+<br>+
connman_dbus_dict_append=
_basic(dict, "mac", DBUS_TYPE_STRING, &addr);<br>+<br>+ connm=
an_dbus_dict_append_basic(dict, "ipv4", DBUS_TYPE_STRING,<br>+
=
&tether_client->ipv4_address);<br>+<br>+ __connman_get_ip_acc=
_info(tether_client);<br>+<br>+ connman_dbus_dict_append_basic(dict, "=
tx-bytes", DBUS_TYPE_UINT64,<br>+
&tether_client->ingr=
ess.bcnt);<br>+<br>+ connman_dbus_dict_append_basic(dict, "rx-bytes&qu=
ot;, DBUS_TYPE_UINT64,<br>+
&tether_client->egress.bcnt);<b=
r>+<br>+ removed_tether_client =3D
g_hash_table_lookup(removed_clients_tabl=
e, addr);<br>+ if (removed_tether_client) {<br>+
connman_dbus_dict_append_=
basic(dict, "previous tx-bytes",<br>+
DBUS_TYPE_UINT64,<b=
r>+
&removed_tether_client->ingress.bcnt);<br>+ connman_dbu=
s_dict_append_basic(dict, "previous rx-bytes",<br>+
DBUS_=
TYPE_UINT64,<br>+
&removed_tether_client->egress.bcnt);<br>+=
} else {<br>+ DBG("no history found for this
client");<br>+ }<b=
r>+}<br>+<br>+static void append_struct_ip_acc_info(char *addr,<br>+
=
struct ip_accounting_info *tether_client,<br>+
DBusMessageIter *i=
ter)<br>+{<br>+ DBusMessageIter entry, dict;<br>+<br>+ dbus_message_iter_op=
en_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);<br>+<br>+
connman_d=
bus_dict_open(&entry, &dict);<br>+<br>+ append_dict_properties(&=
;dict, tether_client, addr);<br>+<br>+ connman_dbus_dict_close(&entry, =
&dict);<br>+<br>+ dbus_message_iter_close_container(iter, &entry);<=
br>+}<br>+<br>=C2=A0static void append_client(gpointer key, gpointer value,=
<br>=C2=A0 gpointer
user_data)<br>=C2=A0{<br>@@ -360,7 +507,11 @@ stat=
ic void append_client(gpointer key, gpointer value,<br>=C2=A0<br>=C2=A0void=
__connman_tethering_list_clients(DBusMessageIter *array)<br>=C2=A0{<br>-
g=
_hash_table_foreach(clients_table, append_client, array);<br>+ DBG("fo=
und %d clients in =C2=A0hash table",<br>+
g_hash_table_size(added_=
clients_table));<br>+<br>+ g_hash_table_foreach(added_clients_table,
append=
_struct_ip_acc_info,<br>+
array);<br>=C2=A0}<br>=C2=A0<br>=C2=A0=
static void setup_tun_interface(unsigned int flags, unsigned change,<br>@@ =
-494,7 +645,7 @@ static gboolean client_send_changed(gpointer data)<br>=C2=
=A0 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,<br>=C2=A0
=
DBUS_TYPE_STRING_AS_STRING, &array);<br>=C2=A0<br>-
g_hash_table_for=
each(clients_table, append_client, &array);<br>+ g_hash_table_foreach(a=
dded_clients_table, append_client, &array);<br>=C2=A0<br>=C2=A0 dbus_me=
ssage_iter_close_container(&iter, &array);<br>=C2=A0<br>@@ -631,14 =
+782,68 @@ int __connman_private_network_release(const char *path)<br>=C2=
=A0<br>=C2=A0void __connman_tethering_client_register(const char *addr)<br>=
=C2=A0{<br>- g_hash_table_insert(clients_table, g_strdup(addr), NULL);<br>+=
struct ip_accounting_info *tether_client;<br>+<br>+
DBG("adding %s ma=
c address in hash table", addr);<br>+<br>+ tether_client =3D tether_cl=
ient_create();<br>+<br>+ if (tether_client)<br>+
g_hash_table_insert(added=
_clients_table, g_strdup(addr), tether_client);<br>+ else<br>+
DBG("c=
ould not create tether client entry");<br>+<br>+ DBG("hash table =
size %d", g_hash_table_size(added_clients_table));<br>+<br>=C2=A0 clie=
nt_added(addr);<br>=C2=A0}<br>=C2=A0<br>=C2=A0void __connman_tethering_clie=
nt_unregister(const char *addr)<br>=C2=A0{<br>- client_removed(addr);<br>-
=
g_hash_table_remove(clients_table, addr);<br>+ struct ip_accounting_info *e=
xisting_tether_client;<br>+ struct ip_accounting_info *old_tether_client;<b=
r>+ struct ip_accounting_info *tether_client;<br>+<br>+
DBG("removing =
%s mac address from hash table", addr);<br>+<br>+ existing_tether_clie=
nt =3D g_hash_table_lookup(added_clients_table, addr);<br>+ if (existing_te=
ther_client) {<br>+ if
(strcmp(existing_tether_client->ipv4_address,<br=
>+
>g_strdup(IP_NOT_OFFERED))) {<br>+
>__connman_get_ip_acc_info(ex=
isting_tether_client);<br>+
__connman_delete_ip_acc_rules(existing_tether=
_client->ipv4_address);<br>+ old_tether_client =3D
g_hash_table_lookup=
(removed_clients_table, addr);<br>+ if (old_tether_client)
{<br>+ DBG(=
"replacing existing client in hash table");<br>+
tether_client=
=3D tether_client_create();<br>+ if
(tether_client) {<br>+ tether_c=
lient->ingress.bcnt =3D old_tether_client->ingress.bcnt<br>+
=
+ existing_tether_client->ingress.bcnt;<br>+
tether_client->egr=
ess.bcnt =3D old_tether_client->egress.bcnt<br>+
+ existing_te=
ther_client->egress.bcnt;<br>+
g_hash_table_replace(removed_clients_=
table,<br>+
g_strdup(addr),<br>+
tether_client);<br>+ =
} else<br>+ DBG("could
not create tether client entry");<br=
>+ } else {<br>+
>DBG("adding client in hash table");<br>+ =
tether_client =3D tether_client_create();<br>+
if (tether_client) {<br>=
+ tether_client->ingress.bcnt =3D
existing_tether_client->ingress=
.bcnt;<br>+ tether_client->egress.bcnt
=3D existing_tether_client-&g=
t;egress.bcnt;<br>+
g_hash_table_insert(removed_clients_table,<br>+ =
g_strdup(addr),<br>+
tether_client);<br>+ } else<br>+ =
DBG("could not create tether client
entry");<br>+ }<br>+ } =
else<br>+ DBG("ip address not offered for %s ",
addr);<br>+ g_=
hash_table_remove(added_clients_table, addr);<br>+
client_removed(addr);<b=
r>+ } else<br>+ DBG("could not remove client from hash
table");<=
br>=C2=A0}<br>=C2=A0<br>=C2=A0int __connman_tethering_init(void)<br>@@ -654=
,8 +859,11 @@ int __connman_tethering_init(void)<br>=C2=A0 pn_hash =3D
g_ha=
sh_table_new_full(g_str_hash, g_str_equal,<br>=C2=A0
NULL, remove_priv=
ate_network);<br>=C2=A0<br>- clients_table =3D g_hash_table_new_full(g_str_=
hash, g_str_equal,<br>- g_free,
NULL);<br>+ added_clients_table =3D g=
_hash_table_new_full(g_str_hash, g_str_equal,<br>+
g_free, tether_cli=
ent_destroy);<br>+<br>+ removed_clients_table =3D g_hash_table_new_full(g_s=
tr_hash, g_str_equal,<br>+
g_free, tether_client_destroy);<br>=C2=A0<=
br>=C2=A0 clients_notify =3D g_new0(struct _clients_notify, 1);<br>=C2=A0
c=
lients_notify->remove =3D g_hash_table_new_full(g_str_hash, g_str_equal,=
<br>@@ -685,8 +893,11 @@ void __connman_tethering_cleanup(void)<br>=C2=A0
g=
_free(clients_notify);<br>=C2=A0 clients_notify =3D NULL;<br>=C2=A0<br>-
g_=
hash_table_destroy(clients_table);<br>- clients_table =3D NULL;<br>+ g_hash=
_table_destroy(added_clients_table);<br>+ added_clients_table =3D
NULL;<br>=
+<br>+ g_hash_table_destroy(removed_clients_table);<br>+
removed_clients_ta=
ble =3D NULL;<br>=C2=A0<br>=C2=A0
dbus_connection_unref(connection);<br>=C2=
=A0}<br><div><br></div>-- <br><div dir=3D"ltr" class=3D"gmail_signature" da=
ta-smartmail=3D"gmail_signature"><div dir=3D"ltr">Thanks,<div>Aravind</div>=
</div></div></div>
--000000000000ff5ca605a69e52b6--
------------------------------
Subject: Digest Footer
_______________________________________________
connman mailing list -- [email protected]
To unsubscribe send an email to [email protected]
------------------------------
End of connman Digest, Vol 55, Issue 16
***************************************