[Add] tethering client monitoring 80/187180/6
authorMilind Murhekar <m.murhekar@samsung.com>
Mon, 20 Aug 2018 11:45:05 +0000 (17:15 +0530)
committerMilind Murhekar <m.murhekar@samsung.com>
Tue, 28 Aug 2018 04:50:16 +0000 (04:50 +0000)
This change adds the feature to monitor
the data usage of connected tethering clients
and saves the stats to the table counters.

Change-Id: I50df631b27ad9fe483f6790877e92308b8ea760a
Signed-off-by: Milind Murhekar <m.murhekar@samsung.com>
12 files changed:
include/stc-manager.h
packaging/stc-manager.spec
plugin/tether/stc-plugin-tether.c
src/helper/helper-cgroup.c
src/helper/helper-cgroup.h
src/helper/helper-iptables.c
src/helper/helper-iptables.h
src/helper/helper-net-cls.c
src/helper/helper-nfacct-rule.c
src/helper/helper-nfacct-rule.h
src/monitor/include/stc-monitor.h
src/monitor/stc-monitor.c

index 898e7ae..94c57a1 100644 (file)
@@ -24,6 +24,7 @@
 #define NET_CLS_SUBSYS "net_cls"
 
 #define STC_BACKGROUND_APP_SUFFIX "_BACKGROUND"
+#define STC_TETHERING_APP_SUFFIX "_TETHERING"
 #define STC_BACKGROUND_APP_ID "BACKGROUND"
 #define STC_TOTAL_DATACALL "TOTAL_DATACALL"
 #define STC_TOTAL_WIFI "TOTAL_WIFI"
@@ -118,6 +119,7 @@ typedef enum {
        STC_APP_TYPE_GROUP,
        STC_APP_TYPE_WATCH,
        STC_APP_TYPE_WIDGET,
+       STC_APP_TYPE_TETHERING,
        STC_APP_TYPE_MAX,
 } stc_app_type_e;
 
index 6b0b965..81d341a 100644 (file)
@@ -1,6 +1,6 @@
 Name:       stc-manager
 Summary:    STC(Smart Traffic Control) manager
-Version:    0.0.74
+Version:    0.0.75
 Release:    0
 Group:      Network & Connectivity/Other
 License:    Apache-2.0
index ed3ccd4..629abbf 100644 (file)
@@ -31,6 +31,51 @@ static GDBusConnection *connection = NULL;
 static GCancellable *cancellable = NULL;
 static int g_mobileap_signal_sub_id = 0;
 
+static stc_error_e add_station_monitor(gchar *pkg_id, gchar *app_id, const char *ip)
+{
+       int ret;
+       stc_app_key_s app_key;
+       stc_app_value_s app_value;
+
+       if (pkg_id == NULL || app_id == NULL || ip == NULL) {
+               STC_LOGE("invalid station station info");
+               return STC_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&app_key, 0, sizeof(stc_app_key_s));
+       memset(&app_value, 0, sizeof(stc_app_value_s));
+       app_key.pkg_id = g_strdup(pkg_id);
+       app_key.app_id = g_strconcat(app_id, STC_TETHERING_APP_SUFFIX, NULL);
+       app_value.type = STC_APP_TYPE_TETHERING;
+       app_value.processes = NULL;
+       g_strlcpy(app_value.ipaddr, ip, IPV4_IPADDRESS_LEN);
+
+       ret = stc_monitor_application_add(app_key, app_value);
+       FREE(app_key.pkg_id);
+       FREE(app_key.app_id);
+       return ret;
+}
+
+static stc_error_e remove_station_monitor(gchar *pkg_id, gchar *app_id)
+{
+       int ret;
+       stc_app_key_s app_key;
+
+       if (pkg_id == NULL || app_id == NULL) {
+               STC_LOGE("invalid station station info");
+               return STC_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&app_key, 0, sizeof(stc_app_key_s));
+       app_key.pkg_id = g_strdup(pkg_id);
+       app_key.app_id = g_strconcat(app_id, STC_TETHERING_APP_SUFFIX, NULL);
+
+       ret = stc_monitor_application_remove(app_key);
+       FREE(app_key.pkg_id);
+       FREE(app_key.app_id);
+       return ret;
+}
+
 static int _compare_sta_by_mac_func(gconstpointer a,
                gconstpointer b)
 {
@@ -75,6 +120,10 @@ static void _remove_station_info(gconstpointer data, GCompareFunc func)
 
        info = (tether_sta_info_s *)list->data;
        STC_LOGI("STA-REMOVED: (%s) (%s) (%s)", info->ip, info->mac, info->name);
+
+       /* remove tethering client from monitoring */
+       remove_station_monitor(info->mac, info->station_id);
+
        g_free(info->station_id);
        g_free(info);
 
@@ -99,7 +148,10 @@ static void _add_station_info(tether_sta_info_s *info)
 
        station_list = g_slist_prepend(station_list, info);
        STC_LOGI("STA-ADDED: (%s) (%s) (%s)", info->ip, info->mac, info->name);
+
+       /* add tethering client for monitoring data usage */
        info->station_id = g_strdup_printf("%s_%s", info->mac, info->name);
+       add_station_monitor(info->mac, info->station_id, info->ip);
 }
 
 static void _mobileap_signal_cb(GDBusConnection *conn,
@@ -189,7 +241,6 @@ void tether_plugin_deinit(void)
        STC_LOGI("tether plugin deinitialised");
 }
 
-/* Tether Plugin APIs */
 API stc_plugin_tether_s tether_plugin = {
        .init = tether_plugin_init,
        .deinit = tether_plugin_deinit,
index 1f195ba..fa54c12 100644 (file)
@@ -237,4 +237,8 @@ void cgroup_init(void)
        /* create foreground cgroup directory */
        cgroup_make_subdir(STC_CGROUP_NETWORK, STC_FOREGROUND_CGROUP_NAME,
                           NULL);
+
+       /* create tethering cgroup directory */
+       cgroup_make_subdir(STC_CGROUP_NETWORK, STC_TETHERING_CGROUP_NAME,
+                          NULL);
 }
index 725cad4..73abd40 100644 (file)
 #define STC_CGROUP_NETWORK              CGROUP_NETWORK "/stc"
 #define BACKGROUND_CGROUP_NETWORK       STC_CGROUP_NETWORK "/BACKGROUND"
 #define FOREGROUND_CGROUP_NETWORK       STC_CGROUP_NETWORK "/FOREGROUND"
+#define TETHERING_CGROUP_NETWORK        STC_CGROUP_NETWORK "/TETHERING"
 #define PROC_TASK_CHILDREN              "/proc/%d/task/%d/children"
 #define STC_CGROUP_NAME                 "stc"
 #define STC_BACKGROUND_CGROUP_NAME      "BACKGROUND"
 #define STC_FOREGROUND_CGROUP_NAME      "FOREGROUND"
+#define STC_TETHERING_CGROUP_NAME       "TETHERING"
 
 /**
  * @desc Get one unsigned int32 value from cgroup
index 6ca96af..0914100 100644 (file)
 #define RULE_CGROUP     "cgroup"
 #define RULE_NFACCT     "nfacct"
 #define RULE_TARGET     "target"
+#define RULE_PROTOCOL   "protocol"
+#define RULE_SIPTYPE    "s_ip_type"
+#define RULE_SIP1       "s_ip1"
+#define RULE_SIP2       "s_ip2"
+#define RULE_DIPTYPE    "d_ip_type"
+#define RULE_DIP1       "d_ip1"
+#define RULE_DIP2       "d_ip2"
 
 static void __add_rule_info_to_builder(GVariantBuilder *builder,
                                       iptables_rule_s *rule)
@@ -68,6 +75,27 @@ static void __add_rule_info_to_builder(GVariantBuilder *builder,
                g_variant_builder_add(builder, "{sv}", RULE_TARGET,
                                      g_variant_new_string(rule->target));
 
+       g_variant_builder_add(builder, "{sv}", RULE_SIPTYPE,
+                                     g_variant_new_uint16(rule->s_iprange_type));
+
+       g_variant_builder_add(builder, "{sv}", RULE_DIPTYPE,
+                                     g_variant_new_uint16(rule->d_iprange_type));
+
+       if (rule->s_ip1.s_addr)
+               g_variant_builder_add(builder, "{sv}", RULE_SIP1,
+                                     g_variant_new_uint32(rule->s_ip1.s_addr));
+
+       if (rule->s_ip2.s_addr)
+               g_variant_builder_add(builder, "{sv}", RULE_SIP2,
+                                     g_variant_new_uint32(rule->s_ip2.s_addr));
+
+       if (rule->d_ip1.s_addr)
+               g_variant_builder_add(builder, "{sv}", RULE_DIP1,
+                                     g_variant_new_uint32(rule->d_ip1.s_addr));
+
+       if (rule->d_ip2.s_addr)
+               g_variant_builder_add(builder, "{sv}", RULE_DIP2,
+                                     g_variant_new_uint32(rule->d_ip2.s_addr));
 }
 
 static int __iptables_rule_add(GDBusConnection *connection,
@@ -436,6 +464,10 @@ stc_error_e iptables_flush_chains(void)
        if (ret != STC_ERROR_NONE)
                goto done; //LCOV_EXCL_LINE
 
+       ret = __iptables_flush_chain(stc->connection, STC_TETHER_CHAIN);
+       if (ret != STC_ERROR_NONE)
+               goto done; //LCOV_EXCL_LINE
+
        ret = __ip6tables_flush_chain(stc->connection, STC_IN_CHAIN);
        if (ret != STC_ERROR_NONE)
                goto done; //LCOV_EXCL_LINE
@@ -479,6 +511,12 @@ stc_error_e iptables_init(void)
                goto done; //LCOV_EXCL_LINE
        }
 
+       ret = __iptables_add_chain(stc->connection, STC_TETHER_CHAIN);
+       if (ret != STC_ERROR_NONE) {
+               __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
+               goto done; //LCOV_EXCL_LINE
+       }
+
        ret = __ip6tables_add_chain(stc->connection, STC_IN_CHAIN);
        if (ret != STC_ERROR_NONE) {
                __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
@@ -510,6 +548,16 @@ stc_error_e iptables_init(void)
        }
 
        ret = __iptables_add_chain_jump_rule("FORWARD", STC_FRWD_CHAIN);
+       if (ret != STC_ERROR_NONE) {
+               __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
+               goto done; //LCOV_EXCL_LINE
+       }
+
+       ret = __iptables_add_chain_jump_rule("FORWARD", STC_TETHER_CHAIN);
+       if (ret != STC_ERROR_NONE) {
+               __STC_LOG_FUNC_EXIT__;
+               goto done;
+       }
 done:
        return ret;
 }
@@ -538,6 +586,12 @@ stc_error_e iptables_deinit(void)
                goto done; //LCOV_EXCL_LINE
        }
 
+       ret = __iptables_remove_chain(stc->connection, STC_TETHER_CHAIN);
+       if (ret != STC_ERROR_NONE) {
+               __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
+               goto done; //LCOV_EXCL_LINE
+       }
+
        ret = __iptables_remove_chain(stc->connection, STC_FRWD_CHAIN);
        if (ret != STC_ERROR_NONE) {
                __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
index 13db25b..71b057b 100644 (file)
 #ifndef __STC_HELPER_IPTABLES_H__
 #define __STC_HELPER_IPTABLES_H__
 
+#include <arpa/inet.h>
 #include "stc-manager.h"
 #include "stc-error.h"
 
 #define STC_IN_CHAIN     "STC_IN"
 #define STC_OUT_CHAIN    "STC_OUT"
 #define STC_FRWD_CHAIN    "STC_FRWD"
+#define STC_TETHER_CHAIN  "STC_TETHER"
 
 typedef enum {
        IPTABLES_DIRECTION_NONE,
@@ -38,11 +40,24 @@ typedef enum {
        IP_TYPE_LAST_ELEM
 } iptables_ip_type_e;
 
+typedef enum {
+       IPTABLES_IP_NONE,
+       IPTABLES_IP_SINGLE,
+       IPTABLES_IP_MASK,
+       IPTABLES_IP_RANGE
+} iptables_iprange_type_e;
+
 typedef struct {
        char *chain;
        char *ifname;
        char *nfacct_name;
        char *target;
+       iptables_iprange_type_e s_iprange_type;
+       iptables_iprange_type_e d_iprange_type;
+       struct in_addr s_ip1;
+       struct in_addr s_ip2;
+       struct in_addr d_ip1;
+       struct in_addr d_ip2;
        iptables_rule_direction_e direction;
        uint32_t classid;
 } iptables_rule_s;
index 748f95f..238b7de 100644 (file)
@@ -137,6 +137,8 @@ uint32_t get_classid_by_app_id(const char *app_id, int create)
 
        if (strstr(app_id, STC_BACKGROUND_APP_SUFFIX))
                path_to_net_cgroup_dir = BACKGROUND_CGROUP_NETWORK;
+       else if (strstr(app_id, STC_TETHERING_APP_SUFFIX))
+               path_to_net_cgroup_dir = TETHERING_CGROUP_NETWORK;
        else
                path_to_net_cgroup_dir = FOREGROUND_CGROUP_NETWORK;
 
@@ -186,6 +188,8 @@ stc_error_e place_pids_to_net_cgroup(const int pid, const char *app_id)
                path_to_net_cgroup_dir = STC_CGROUP_NETWORK;
        else if (strstr(app_id, STC_BACKGROUND_APP_SUFFIX))
                path_to_net_cgroup_dir = BACKGROUND_CGROUP_NETWORK;
+       else if (strstr(app_id, STC_TETHERING_APP_SUFFIX))
+               path_to_net_cgroup_dir = TETHERING_CGROUP_NETWORK;
        else
                path_to_net_cgroup_dir = FOREGROUND_CGROUP_NETWORK; //LCOV_EXCL_LINE
 
index 90364d3..70b29a5 100644 (file)
@@ -448,12 +448,32 @@ static stc_error_e exec_iptables_cmd(nfacct_rule_s *rule)
        iptables_rule.nfacct_name = g_strdup(rule->name);
        iptables_rule.ifname = g_strdup(rule->ifname);
        iptables_rule.target = g_strdup(get_iptables_jump(rule->jump));
-       iptables_rule.chain = g_strdup(get_iptables_chain(rule->iotype));
+
+       /* In case of tehering use chain 'STC_TETHER' */
+       if (rule->intend == NFACCT_TETH_COUNTER)
+               iptables_rule.chain = g_strdup(STC_TETHER_CHAIN);
+       else
+               iptables_rule.chain = g_strdup(get_iptables_chain(rule->iotype));
+
        iptables_rule.classid = rule->classid;
        iptables_rule.direction = (rule->iotype & NFACCT_COUNTER_IN) ?
                                        IPTABLES_DIRECTION_IN : IPTABLES_DIRECTION_OUT;
        iptype = (iptables_ip_type_e)rule->iptype;
 
+       /* specify the ip range type for source and destination */
+       iptables_rule.s_iprange_type = rule->src_iprange_type;
+       iptables_rule.d_iprange_type = rule->dst_iprange_type;
+
+       /* specify source and destination ip address if any */
+       if (rule->src_ip1)
+               inet_aton(rule->src_ip1, &iptables_rule.s_ip1);
+       if (rule->src_ip2)
+               inet_aton(rule->src_ip2, &iptables_rule.s_ip2);
+       if (rule->dst_ip1)
+               inet_aton(rule->dst_ip1, &iptables_rule.d_ip1);
+       if (rule->dst_ip2)
+               inet_aton(rule->dst_ip2, &iptables_rule.d_ip2);
+
        if (rule->action == NFACCT_ACTION_DELETE) {
                /* delete interface rule */
                ret = iptables_remove(&iptables_rule, iptype);
@@ -480,6 +500,7 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule)
        char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
                3*MAX_DEC_SIZE(int) + 4 + 1];
        stc_error_e ret = STC_ERROR_NONE;
+       uint32_t classid = rule->classid;
 
        /* income part */
        if (rule->iotype & NFACCT_COUNTER_IN) {
@@ -508,7 +529,19 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule)
                ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
                                 STC_ERROR_FAIL, "Not enought buffer");
 
+               /* cgroup extention on FORWARD chain are not allowed
+                * remove classid info in case of tethering rules */
+               if (rule->intend == NFACCT_TETH_COUNTER) {
+                       classid = rule->classid;
+                       rule->classid = 0;
+               }
+
                ret = exec_iptables_cmd(rule);
+
+               /* restore the classid info in case of tethering rule */
+               if (rule->intend == NFACCT_TETH_COUNTER)
+                       rule->classid = classid;
+
                ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
                                 "Can't set conditional block for ingress"
                                 " traffic, for classid %u, cmd %s, j %s",
@@ -551,7 +584,19 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule)
                ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
                                 STC_ERROR_FAIL, "Not enought buffer");
 
+               /* cgroup extention on FORWARD chain are not allowed
+                * remove classid info in case of tethering rules */
+               if (rule->intend == NFACCT_TETH_COUNTER) {
+                       classid = rule->classid;
+                       rule->classid = 0;
+               }
+
                ret = exec_iptables_cmd(rule);
+
+               /* restore the classid info in case of tethering rule */
+               if (rule->intend == NFACCT_TETH_COUNTER)
+                       rule->classid = classid;
+
                ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
                                 "Can't set conditional block for engress"
                                 " traffic, for classid %u, cmd %s, j %s",
index 9d80afb..52ef8f4 100644 (file)
@@ -67,6 +67,13 @@ typedef enum {
        NFACCT_TYPE_LAST_ELEM
 } nfacct_rule_iptype;
 
+typedef enum {
+       NFACCT_IPRANGE_TYPE_NONE,
+       NFACCT_IPRANGE_TYPE_SINGLE,
+       NFACCT_IPRANGE_TYPE_MASK,
+       NFACCT_IPRANGE_TYPE_RANGE,
+} nfacct_rule_iprange_type;
+
 enum nfnl_acct_flags {
        NFACCT_F_QUOTA_PKTS     = (1 << 0),
        NFACCT_F_QUOTA_BYTES    = (1 << 1),
@@ -97,6 +104,12 @@ struct nfacct_rule {
        nfacct_rule_jump jump; /* in most cases jump is evalutation based on intend, but not always */
        stc_rstn_state_e rstn_state;
        nfacct_rule_iptype iptype;
+       nfacct_rule_iprange_type src_iprange_type;
+       nfacct_rule_iprange_type dst_iprange_type;
+       char *src_ip1;
+       char *src_ip2;
+       char *dst_ip1;
+       char *dst_ip2;
 
        struct counter_arg *carg;
        stc_error_e(*iptables_rule)(struct nfacct_rule *counter);
index 3414c06..4b5375c 100644 (file)
@@ -27,6 +27,7 @@
 
 /* 1 seconds */
 #define CONTR_TIMER_INTERVAL 1
+#define IPV4_IPADDRESS_LEN 16
 
 /**
  * @brief enumeration for data limit types
@@ -72,6 +73,7 @@ typedef struct {
        stc_data_counter_s data_usage;
        stc_data_counter_s counter;
        GTree *processes;  /**< applications instances */
+       char ipaddr[IPV4_IPADDRESS_LEN+1]; /**< application ip address */
 } stc_app_value_s;
 
 /**
@@ -139,6 +141,11 @@ stc_error_e stc_monitor_application_add(const stc_app_key_s app_key,
                                        const stc_app_value_s app_value);
 
 /**
+ * @brief deletes an application entry
+ */
+stc_error_e stc_monitor_application_remove(const stc_app_key_s app_key);
+
+/**
  * @brief associates process to an application
  */
 stc_error_e stc_monitor_process_add(const stc_app_key_s app_key,
index 2a42682..fbed5e3 100644 (file)
@@ -70,6 +70,102 @@ static nfacct_rule_jump __get_jump_by_intend(struct nfacct_rule *counter)
        return NFACCT_JUMP_UNKNOWN;
 }
 
+static stc_error_e __add_iptables_tether_in(struct nfacct_rule *counter,
+               const gchar *ipaddr)
+{
+       int ret;
+
+       if (counter == NULL || ipaddr == NULL)
+               return STC_ERROR_INVALID_PARAMETER;
+
+       counter->action = NFACCT_ACTION_INSERT;
+       counter->iotype = NFACCT_COUNTER_IN;
+       counter->jump = __get_jump_by_intend(counter);
+       counter->iptype = NFACCT_TYPE_IPV4;
+       counter->send_limit = 0;
+       counter->rcv_limit = 0;
+       counter->src_iprange_type = NFACCT_IPRANGE_TYPE_SINGLE;
+       counter->src_ip1 = g_strdup(ipaddr);
+
+       ret = produce_net_rule(counter);
+
+       g_free(counter->src_ip1);
+       counter->src_iprange_type = NFACCT_IPRANGE_TYPE_NONE;
+       return ret;
+}
+
+static stc_error_e __add_iptables_tether_out(struct nfacct_rule *counter,
+               const gchar *ipaddr)
+{
+       int ret;
+
+       if (counter == NULL || ipaddr == NULL)
+               return STC_ERROR_INVALID_PARAMETER;
+
+       counter->action = NFACCT_ACTION_INSERT;
+       counter->iotype = NFACCT_COUNTER_OUT;
+       counter->jump = __get_jump_by_intend(counter);
+       counter->iptype = NFACCT_TYPE_IPV4;
+       counter->send_limit = 0;
+       counter->rcv_limit = 0;
+       counter->dst_iprange_type = NFACCT_IPRANGE_TYPE_SINGLE;
+       counter->dst_ip1 = g_strdup(ipaddr);
+
+       ret = produce_net_rule(counter);
+
+       g_free(counter->dst_ip1);
+       counter->dst_iprange_type = NFACCT_IPRANGE_TYPE_NONE;
+       return ret;
+}
+
+static stc_error_e __del_iptables_tether_in(struct nfacct_rule *counter,
+               const gchar *ipaddr)
+{
+       int ret;
+
+       if (counter == NULL || ipaddr == NULL)
+               return STC_ERROR_INVALID_PARAMETER;
+
+       counter->action = NFACCT_ACTION_DELETE;
+       counter->iotype = NFACCT_COUNTER_IN;
+       counter->jump = __get_jump_by_intend(counter);
+       counter->iptype = NFACCT_TYPE_IPV4;
+       counter->send_limit = 0;
+       counter->rcv_limit = 0;
+       counter->src_iprange_type = NFACCT_IPRANGE_TYPE_SINGLE;
+       counter->src_ip1 = g_strdup(ipaddr);
+
+       ret = produce_net_rule(counter);
+
+       g_free(counter->src_ip1);
+       counter->src_iprange_type = NFACCT_IPRANGE_TYPE_NONE;
+       return ret;
+}
+
+static stc_error_e __del_iptables_tether_out(struct nfacct_rule *counter,
+               const gchar *ipaddr)
+{
+       int ret;
+
+       if (counter == NULL || ipaddr == NULL)
+               return STC_ERROR_INVALID_PARAMETER;
+
+       counter->action = NFACCT_ACTION_DELETE;
+       counter->iotype = NFACCT_COUNTER_OUT;
+       counter->jump = __get_jump_by_intend(counter);
+       counter->iptype = NFACCT_TYPE_IPV4;
+       counter->send_limit = 0;
+       counter->rcv_limit = 0;
+       counter->dst_iprange_type = NFACCT_IPRANGE_TYPE_SINGLE;
+       counter->dst_ip1 = g_strdup(ipaddr);
+
+       ret = produce_net_rule(counter);
+
+       g_free(counter->dst_ip1);
+       counter->dst_iprange_type = NFACCT_IPRANGE_TYPE_NONE;
+       return ret;
+}
+
 static stc_error_e __add_iptables_in(struct nfacct_rule *counter)
 {
        if (counter == NULL)
@@ -384,10 +480,93 @@ static gboolean __processes_tree_check_empty(gpointer key, gpointer value,
 }
 //LCOV_EXCL_STOP
 
+static gboolean __add_application_monitor_for_tethering(gpointer key, gpointer value,
+                                   gpointer data)
+{
+       stc_app_value_s *app_value = (stc_app_value_s *)value;
+       stc_app_key_s *app_key = (stc_app_key_s *)key;
+       default_connection_s *connection = (default_connection_s *)data;
+       stc_s *stc = stc_get_manager();
+       struct nfacct_rule counter;
+
+       STC_LOGI("add tether app (%s)", app_key->app_id);
+
+       if (stc == NULL || connection == NULL)
+               return FALSE;
+
+       if (!stc->carg) {
+               stc->carg = MALLOC0(counter_arg_s, 1);
+               if (stc->carg == NULL)
+                       return FALSE;
+
+               stc->carg->sock = stc_monitor_get_counter_socket();
+       }
+
+       memset(&counter, 0, sizeof(struct nfacct_rule));
+
+       counter.carg = stc->carg;
+       counter.classid = app_value->classid;
+       counter.intend = NFACCT_TETH_COUNTER;
+
+       if (connection->tether_state != TRUE ||
+                       connection->tether_iface.ifname == NULL)
+               return FALSE;
+
+       counter.iftype = connection->tether_iface.type;
+       g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
+
+       __add_iptables_tether_in(&counter, app_value->ipaddr);
+       __add_iptables_tether_out(&counter, app_value->ipaddr);
+
+       return FALSE;
+}
+
+static gboolean __remove_application_monitor_for_tethering(gpointer key, gpointer value,
+                                   gpointer data)
+{
+       stc_app_value_s *app_value = (stc_app_value_s *)value;
+       stc_app_key_s *app_key = (stc_app_key_s *)key;
+       default_connection_s *connection = (default_connection_s *)data;
+       stc_s *stc = stc_get_manager();
+       struct nfacct_rule counter;
+
+       STC_LOGI("remove tether app (%s)", app_key->app_id);
+
+       if (stc == NULL || connection == NULL)
+               return FALSE;
+
+       if (!stc->carg) {
+               stc->carg = MALLOC0(counter_arg_s, 1);
+               if (stc->carg == NULL)
+                       return FALSE;
+
+               stc->carg->sock = stc_monitor_get_counter_socket();
+       }
+
+       memset(&counter, 0, sizeof(struct nfacct_rule));
+
+       counter.carg = stc->carg;
+       counter.classid = app_value->classid;
+       counter.intend = NFACCT_TETH_COUNTER;
+
+       if (connection->tether_state != TRUE ||
+                       connection->tether_iface.ifname == NULL)
+               return FALSE;
+
+       counter.iftype = connection->tether_iface.type;
+       g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
+
+       __del_iptables_tether_in(&counter, app_value->ipaddr);
+       __del_iptables_tether_out(&counter, app_value->ipaddr);
+
+       return FALSE;
+}
+
 static gboolean __add_application_monitor(gpointer key, gpointer value,
                                          gpointer data)
 {
        stc_app_value_s *app_value = (stc_app_value_s *)value;
+       stc_app_key_s *app_key = (stc_app_key_s *)key;
        default_connection_s *connection = (default_connection_s *)data;
        stc_s *stc = stc_get_manager();
 
@@ -423,7 +602,10 @@ static gboolean __add_application_monitor(gpointer key, gpointer value,
                        g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
                }
 
-               if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
+               if (g_str_has_suffix(app_key->app_id, STC_TETHERING_APP_SUFFIX) &&
+                               app_value->classid != STC_TETHERING_APP_CLASSID) {
+                       __add_application_monitor_for_tethering(key, value, data);
+               } else if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
                        __add_iptables_in(&counter);
                        __add_iptables_out(&counter);
                } else if (app_value->classid == STC_TOTAL_IPV6_CLASSID) {
@@ -444,6 +626,7 @@ static gboolean __remove_application_monitor(gpointer key, gpointer value,
                                             gpointer data)
 {
        stc_app_value_s *app_value = (stc_app_value_s *)value;
+       stc_app_key_s *app_key = (stc_app_key_s *)key;
        default_connection_s *connection = (default_connection_s *)data;
        stc_s *stc = stc_get_manager();
 
@@ -464,7 +647,11 @@ static gboolean __remove_application_monitor(gpointer key, gpointer value,
                counter.classid = app_value->classid;
                counter.intend = NFACCT_COUNTER;
 
-               if (connection->tether_state == FALSE &&
+               if (g_str_has_suffix(app_key->app_id, STC_TETHERING_APP_SUFFIX) &&
+                               app_value->classid != STC_TETHERING_APP_CLASSID) {
+                       __remove_application_monitor_for_tethering(key, value, data);
+                       return FALSE;
+               } else if (connection->tether_state == FALSE &&
                        connection->tether_iface.ifname != NULL &&
                        app_value->classid == STC_TETHERING_APP_CLASSID) {
                        counter.iftype = connection->tether_iface.type;
@@ -1049,7 +1236,8 @@ static gboolean __rstn_counter_update_foreach_classid(gpointer key,
        classid_bytes_context_s *context = (classid_bytes_context_s *)data;
        uint32_t classid;
 
-       if (context->counter->intend != NFACCT_COUNTER)
+       if (context->counter->intend != NFACCT_COUNTER &&
+                       context->counter->intend != NFACCT_TETH_COUNTER)
                goto try_next_callback;
 
        if (rstn_value->limit_exceeded == TRUE) {
@@ -1103,6 +1291,8 @@ static gboolean __update_app_statistics(gpointer key, gpointer value,
        if (app_value->classid == STC_TETHERING_APP_CLASSID &&
                default_connection->tether_state == TRUE)
                stat_key.iftype = default_connection->tether_iface.type;
+       else if (g_str_has_suffix(app_key->app_id, STC_TETHERING_APP_SUFFIX))
+               stat_key.iftype = default_connection->tether_iface.type;
        else
                stat_key.iftype = default_connection->type;
 
@@ -1115,6 +1305,9 @@ static gboolean __update_app_statistics(gpointer key, gpointer value,
                default_connection->tether_state == TRUE)
                g_strlcpy(stat_key.ifname, default_connection->tether_iface.ifname,
                          MAX_IFACE_LENGTH);
+       else if (g_str_has_suffix(app_key->app_id, STC_TETHERING_APP_SUFFIX))
+               g_strlcpy(stat_key.ifname, default_connection->tether_iface.ifname,
+                         MAX_IFACE_LENGTH);
        else
                g_strlcpy(stat_key.ifname, default_connection->ifname,
                          MAX_IFACE_LENGTH);
@@ -1266,7 +1459,8 @@ static gboolean __apps_counter_update_foreach_classid(gpointer key,
        stc_app_value_s *app_value = (stc_app_value_s *)value;
        classid_bytes_context_s *context = (classid_bytes_context_s *)data;
 
-       if (context->counter->intend != NFACCT_COUNTER)
+       if (context->counter->intend != NFACCT_COUNTER &&
+                       context->counter->intend != NFACCT_TETH_COUNTER)
                goto try_next_callback;
 
        __interface_counter_update(app_key, app_value, context);
@@ -2071,6 +2265,7 @@ API stc_error_e stc_monitor_application_add(const stc_app_key_s app_key,
        value->type = app_value.type;
        value->data_usage.in_bytes = app_value.data_usage.in_bytes;
        value->data_usage.out_bytes = app_value.data_usage.out_bytes;
+       g_strlcpy(value->ipaddr, app_value.ipaddr, IPV4_IPADDRESS_LEN);
 
        value->processes = g_tree_new_full(__processes_tree_key_compare, NULL,
                                           __processes_tree_key_free,
@@ -2088,6 +2283,36 @@ API stc_error_e stc_monitor_application_add(const stc_app_key_s app_key,
        return ret;
 }
 
+API stc_error_e stc_monitor_application_remove(const stc_app_key_s app_key)
+{
+       stc_error_e ret = STC_ERROR_NONE;
+       stc_app_value_s *app_lookup;
+
+       ret_value_msg_if(g_system == NULL, STC_ERROR_FAIL, "stc monitor not initialized!");
+
+       app_lookup = __application_lookup(g_system->apps, &app_key);
+       if (!app_lookup) {
+               if (STC_DEBUG_LOG)
+                       STC_LOGD("app_key not found"); //LCOV_EXCL_LINE
+               return STC_ERROR_FAIL; //LCOV_EXCL_LINE
+       }
+
+       /* remove nfacct rule for this classid */
+       __remove_application_monitor((gpointer) &app_key, app_lookup,
+                                    stc_get_default_connection());
+
+       /* remove ristrictions if any */
+       __remove_rstns_for_application(app_key.app_id);
+
+       /* remove app_key from the stc-manager */
+       if (!g_tree_remove(g_system->apps, &app_key)) {
+               ret = STC_ERROR_NO_DATA;
+               STC_LOGE("key not found");
+       }
+
+       return ret;
+}
+
 API stc_error_e stc_monitor_process_add(const stc_app_key_s app_key,
                                    const stc_process_key_s proc_key,
                                    const stc_process_value_s proc_value)