Add tethering client data limitation 17/187917/5
authorMilind Murhekar <m.murhekar@samsung.com>
Wed, 29 Aug 2018 11:03:11 +0000 (16:33 +0530)
committerMilind Murhekar <m.murhekar@samsung.com>
Thu, 30 Aug 2018 04:50:21 +0000 (10:20 +0530)
This change/feature adds the data limitaion restriction
on each connected tethering clients based on its
mac address, ip address and app id.

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

index bdee306..8fd874b 100644 (file)
@@ -24,6 +24,7 @@
 int stc_plugin_tether_init(void);
 int stc_plugin_tether_deinit(void);
 stc_error_e stc_plugin_tether_load(void);
-stc_error_e stc_plugin_tether_status_changed(void);
-
+int stc_plugin_tether_get_station_ip(const char *mac, char **ipaddr);
+int stc_plugin_tether_get_station_by_classid(const int classid, char **mac);
+int stc_plugin_tether_set_station_classid(const char *mac, int classid);
 #endif /* __STC_MANAGER_PLUGIN_TETHER_H__ */
index b57a246..d84c351 100644 (file)
@@ -1,6 +1,6 @@
 Name:       stc-manager
 Summary:    STC(Smart Traffic Control) manager
-Version:    0.0.75
+Version:    0.0.76
 Release:    0
 Group:      Network & Connectivity/Other
 License:    Apache-2.0
index b3d4439..f021516 100644 (file)
 #define __STC_PLUGIN_TETHER_H__
 
 #include <glib.h>
+#include <arpa/inet.h>
 #include "stc-error.h"
 #include "stc-manager.h"
 
 #define TETHERING_SERVICE_INTERFACE   "org.tizen.tethering"
 #define SIGNAL_NAME_DHCP_STATUS       "dhcp_status"
-#define STATION_STR_INFO_LEN          54
+#define STATION_MAC_STR_LEN           18
 #define STATION_STR_HOSTNAME_LEN      33
 
 typedef struct {
-       gchar *station_id;
-       gchar name[STATION_STR_HOSTNAME_LEN + 1];
-       gchar ip[STATION_STR_INFO_LEN + 1];
-       gchar mac[STATION_STR_INFO_LEN + 1];
+       gchar *station_id;                      /* Station unique ID (mac_hostname)*/
+       int classid;                            /* cgroup net_cls Classid of station */
+       gchar name[STATION_STR_HOSTNAME_LEN+1]; /* Station hostname */
+       gchar ip[INET_ADDRSTRLEN+1];            /* Station IP address */
+       gchar mac[STATION_MAC_STR_LEN+1];       /* Station MAC address */
 } tether_sta_info_s;
 
 typedef struct {
        int (*init) (void);
        void (*deinit) (void);
-       int (*status_changed) (void);
+       int (*get_station_ip) (const char *mac, char *ip);
+       int (*get_station_by_classid) (const int classid, char *mac);
+       int (*set_station_classid) (const char *mac, int classid);
 } stc_plugin_tether_s;
 
 int tether_init(void);
 void tether_deinit(void);
-stc_error_e tether_plugin_status_changed(void);
-
+stc_error_e tether_plugin_get_station_ip(const char *mac, char *ip);
+stc_error_e tether_plugin_get_station_by_classid(const int classid, char *mac);
+stc_error_e tether_plugin_set_station_classid(const char *mac, int classid);
 #endif /* __STC_PLUGIN_TETHER_H__ */
index 629abbf..2641509 100644 (file)
@@ -31,13 +31,14 @@ 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)
+static stc_error_e add_station_monitor(gchar *pkg_id, gchar *app_id,
+                        const char *mac)
 {
        int ret;
        stc_app_key_s app_key;
        stc_app_value_s app_value;
 
-       if (pkg_id == NULL || app_id == NULL || ip == NULL) {
+       if (pkg_id == NULL || app_id == NULL || mac == NULL) {
                STC_LOGE("invalid station station info");
                return STC_ERROR_INVALID_PARAMETER;
        }
@@ -48,7 +49,7 @@ static stc_error_e add_station_monitor(gchar *pkg_id, gchar *app_id, const char
        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);
+       g_strlcpy(app_value.mac, mac, STATION_MAC_STR_LEN);
 
        ret = stc_monitor_application_add(app_key, app_value);
        FREE(app_key.pkg_id);
@@ -83,6 +84,14 @@ static int _compare_sta_by_mac_func(gconstpointer a,
        return g_ascii_strcasecmp(si->mac, (const char *)b);
 }
 
+static int _compare_sta_by_classid_func(gconstpointer a,
+               gconstpointer b)
+{
+       tether_sta_info_s *si = (tether_sta_info_s *)a;
+       int *classid = (int *)b;
+       return si->classid - *classid;
+}
+
 static int _get_station_info(gconstpointer data, GCompareFunc func,
                tether_sta_info_s **si)
 {
@@ -142,7 +151,7 @@ static void _add_station_info(tether_sta_info_s *info)
                if (!g_strcmp0(tmp->name, info->name) && !g_strcmp0(tmp->ip, info->ip))
                        return;
 
-               //Remove the station if dhcp info changed.
+               /* Remove the station if dhcp info changed. */
                _remove_station_info(info->mac, _compare_sta_by_mac_func);
        }
 
@@ -151,7 +160,7 @@ static void _add_station_info(tether_sta_info_s *info)
 
        /* 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);
+       add_station_monitor(info->mac, info->station_id, info->mac);
 }
 
 static void _mobileap_signal_cb(GDBusConnection *conn,
@@ -182,8 +191,8 @@ static void _mobileap_signal_cb(GDBusConnection *conn,
        STC_LOGI("%s: ip(%s) mac(%s) name(%s) tm(%d)", state, ip, mac, hostname, tm);
 
        if (!g_strcmp0(state, "DhcpConnected")) {
-               g_strlcpy(sta->ip, ip, STATION_STR_INFO_LEN);
-               g_strlcpy(sta->mac, mac, STATION_STR_INFO_LEN);
+               g_strlcpy(sta->ip, ip, INET_ADDRSTRLEN);
+               g_strlcpy(sta->mac, mac, STATION_MAC_STR_LEN);
                g_strlcpy(sta->name, hostname, STATION_STR_HOSTNAME_LEN);
                _add_station_info(sta);
        } else if (!g_strcmp0(state, "DhcpLeaseDeleted")) {
@@ -196,8 +205,59 @@ static void _mobileap_signal_cb(GDBusConnection *conn,
        g_free(hostname);
 }
 
-stc_error_e tether_plugin_status_changed(void)
+stc_error_e tether_plugin_get_station_ip(const char *mac, char *ip)
+{
+       tether_sta_info_s *tmp = NULL;
+
+       if (mac == NULL || ip == NULL)
+               return STC_ERROR_FAIL;
+
+       if (_get_station_info((gconstpointer)mac,
+                               _compare_sta_by_mac_func, &tmp) != 0) {
+               STC_LOGE("mac(%s) not found", mac);
+               return STC_ERROR_FAIL;
+       }
+
+       g_strlcpy(ip, tmp->ip, INET_ADDRSTRLEN);
+       return STC_ERROR_NONE;
+}
+
+stc_error_e tether_plugin_get_station_by_classid(const int classid, char *mac)
+{
+       tether_sta_info_s *tmp = NULL;
+       int classid_value = classid;
+
+       if (mac == NULL)
+               return STC_ERROR_FAIL;
+
+       if (_get_station_info((gconstpointer)&classid_value,
+                               _compare_sta_by_classid_func, &tmp) != 0) {
+               STC_LOGE("classid(%s) not found", classid);
+               return STC_ERROR_FAIL;
+       }
+
+       g_strlcpy(mac, tmp->mac, STATION_MAC_STR_LEN);
+       return STC_ERROR_NONE;
+}
+
+stc_error_e tether_plugin_set_station_classid(const char *mac, int classid)
 {
+       tether_sta_info_s *tmp = NULL;
+
+       if (mac == NULL) {
+               STC_LOGE("invalid param");
+               return STC_ERROR_FAIL;
+       }
+
+       if (_get_station_info((gconstpointer)mac,
+                               _compare_sta_by_mac_func, &tmp) != 0) {
+               STC_LOGE("mac(%s) not found", mac);
+               return STC_ERROR_FAIL;
+       }
+
+       if (tmp)
+               tmp->classid = classid;
+
        return STC_ERROR_NONE;
 }
 
@@ -244,5 +304,7 @@ void tether_plugin_deinit(void)
 API stc_plugin_tether_s tether_plugin = {
        .init = tether_plugin_init,
        .deinit = tether_plugin_deinit,
-       .status_changed = tether_plugin_status_changed
+       .get_station_ip = tether_plugin_get_station_ip,
+       .get_station_by_classid = tether_plugin_get_station_by_classid,
+       .set_station_classid = tether_plugin_set_station_classid
 };
index ea36988..fb62bb9 100644 (file)
@@ -21,6 +21,7 @@ typedef struct {
        char *app_id;
        char *ifname;
        char *subscriber_id;
+       char *mac;
        stc_iface_type_e iftype;
        stc_rstn_type_e rstn_type;
        stc_roaming_type_e roaming;
index 0914100..445b627 100644 (file)
@@ -39,7 +39,6 @@
 #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"
index 70b29a5..d75c3f3 100644 (file)
@@ -285,6 +285,14 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
 
        STRING_SAVE_COPY(cnt->name, cnt_name);
 
+#if 0
+       /* ========================================================
+        * NOTE:-
+        * Below parsing for tethering case is not in use
+        * stc-manager needs to ignore this for NFACCT_TETH_COUNTER
+        * this is disbaled for future use.
+        * =======================================================*/
+
        //LCOV_EXCL_START
        if (cnt->intend == NFACCT_TETH_COUNTER) {
                char ifname_buf[MAX_IFACE_LENGTH];
@@ -322,6 +330,7 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
                return true;
        }
        //LCOV_EXCL_STOP
+#endif
 
        io_part = strtok_r(name, "_", &save_ptr);
        if (io_part != NULL)
@@ -449,8 +458,10 @@ static stc_error_e exec_iptables_cmd(nfacct_rule_s *rule)
        iptables_rule.ifname = g_strdup(rule->ifname);
        iptables_rule.target = g_strdup(get_iptables_jump(rule->jump));
 
-       /* In case of tehering use chain 'STC_TETHER' */
-       if (rule->intend == NFACCT_TETH_COUNTER)
+       /* In case of tehering rules use chain 'STC_TETHER' */
+       if (rule->intend == NFACCT_TETH_COUNTER ||
+                       rule->intend == NFACCT_TETH_ALLOW ||
+                       rule->intend == NFACCT_TETH_BLOCK)
                iptables_rule.chain = g_strdup(STC_TETHER_CHAIN);
        else
                iptables_rule.chain = g_strdup(get_iptables_chain(rule->iotype));
@@ -531,7 +542,9 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule)
 
                /* cgroup extention on FORWARD chain are not allowed
                 * remove classid info in case of tethering rules */
-               if (rule->intend == NFACCT_TETH_COUNTER) {
+               if (rule->intend == NFACCT_TETH_COUNTER ||
+                               rule->intend == NFACCT_TETH_ALLOW ||
+                               rule->intend == NFACCT_TETH_BLOCK) {
                        classid = rule->classid;
                        rule->classid = 0;
                }
@@ -539,7 +552,9 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule)
                ret = exec_iptables_cmd(rule);
 
                /* restore the classid info in case of tethering rule */
-               if (rule->intend == NFACCT_TETH_COUNTER)
+               if (rule->intend == NFACCT_TETH_COUNTER ||
+                               rule->intend == NFACCT_TETH_ALLOW ||
+                               rule->intend == NFACCT_TETH_BLOCK)
                        rule->classid = classid;
 
                ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
@@ -586,7 +601,9 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule)
 
                /* cgroup extention on FORWARD chain are not allowed
                 * remove classid info in case of tethering rules */
-               if (rule->intend == NFACCT_TETH_COUNTER) {
+               if (rule->intend == NFACCT_TETH_COUNTER ||
+                               rule->intend == NFACCT_TETH_ALLOW ||
+                               rule->intend == NFACCT_TETH_BLOCK) {
                        classid = rule->classid;
                        rule->classid = 0;
                }
@@ -594,7 +611,9 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule)
                ret = exec_iptables_cmd(rule);
 
                /* restore the classid info in case of tethering rule */
-               if (rule->intend == NFACCT_TETH_COUNTER)
+               if (rule->intend == NFACCT_TETH_COUNTER ||
+                               rule->intend == NFACCT_TETH_ALLOW ||
+                               rule->intend == NFACCT_TETH_BLOCK)
                        rule->classid = classid;
 
                ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
@@ -795,12 +814,17 @@ void generate_counter_name(nfacct_rule_s *counter)
                STRING_SAVE_COPY(counter->ifname, iftype_name);
        }
 
-       if (counter->intend  == NFACCT_WARN)
+       if (counter->intend  == NFACCT_WARN ||
+                       counter->intend == NFACCT_TETH_WARN)
                warn_symbol = 'w';
-       else if (counter->intend  == NFACCT_BLOCK)
+       else if (counter->intend  == NFACCT_BLOCK ||
+                       counter->intend == NFACCT_TETH_BLOCK)
                warn_symbol = 'r';
-       else if (counter->intend  == NFACCT_ALLOW)
+       else if (counter->intend  == NFACCT_ALLOW ||
+                       counter->intend == NFACCT_TETH_ALLOW)
                warn_symbol = 'a';
+       else if (counter->intend == NFACCT_TETH_COUNTER)
+               warn_symbol = 't';
        snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s",
                 warn_symbol, counter->iotype, counter->iftype,
                 counter->classid, counter->ifname);
index 52ef8f4..7520709 100644 (file)
@@ -56,6 +56,9 @@ typedef enum {
        NFACCT_BLOCK,
        NFACCT_ALLOW,
        NFACCT_TETH_COUNTER,
+       NFACCT_TETH_WARN,
+       NFACCT_TETH_BLOCK,
+       NFACCT_TETH_ALLOW,
        NFACCT_RULE_LAST_ELEM,
 } nfacct_rule_intend;
 
index 187035f..d138cbc 100755 (executable)
@@ -27,7 +27,7 @@
 
 /* 1 seconds */
 #define CONTR_TIMER_INTERVAL 1
-#define IPV4_IPADDRESS_LEN 16
+#define MAC_ADDRESS_LEN 18
 
 /**
  * @brief enumeration for data limit types
@@ -78,7 +78,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 */
+       char mac[MAC_ADDRESS_LEN+1]; /**< application mac address */
 } stc_app_value_s;
 
 /**
@@ -87,6 +87,7 @@ typedef struct {
 typedef struct {
        gchar *app_id;
        gchar *ifname;
+       gchar *mac;
        gchar *subscriber_id;
        stc_iface_type_e iftype;
        stc_roaming_type_e roaming;
index 7f28d9c..8037c53 100755 (executable)
@@ -31,6 +31,7 @@
 #include "stc-time.h"
 #include "stc-manager-plugin-appstatus.h"
 #include "stc-manager-plugin-exception.h"
+#include "stc-manager-plugin-tether.h"
 
 #define GRANULARITY 10
 #define MAX_INT_LENGTH 128
@@ -101,6 +102,10 @@ static nfacct_rule_jump __get_jump_by_intend(struct nfacct_rule *counter)
                return NFACCT_JUMP_REJECT;
        else if (counter->intend == NFACCT_ALLOW)
                return NFACCT_JUMP_ACCEPT;
+       else if (counter->intend == NFACCT_TETH_BLOCK)
+               return NFACCT_JUMP_REJECT;
+       else if (counter->intend == NFACCT_TETH_ALLOW)
+               return NFACCT_JUMP_ACCEPT;
 
        return NFACCT_JUMP_UNKNOWN;
 }
@@ -124,7 +129,7 @@ static stc_error_e __add_iptables_tether_in(struct nfacct_rule *counter,
 
        ret = produce_net_rule(counter);
 
-       g_free(counter->src_ip1);
+       FREE(counter->src_ip1);
        counter->src_iprange_type = NFACCT_IPRANGE_TYPE_NONE;
        return ret;
 }
@@ -148,7 +153,7 @@ static stc_error_e __add_iptables_tether_out(struct nfacct_rule *counter,
 
        ret = produce_net_rule(counter);
 
-       g_free(counter->dst_ip1);
+       FREE(counter->dst_ip1);
        counter->dst_iprange_type = NFACCT_IPRANGE_TYPE_NONE;
        return ret;
 }
@@ -172,7 +177,7 @@ static stc_error_e __del_iptables_tether_in(struct nfacct_rule *counter,
 
        ret = produce_net_rule(counter);
 
-       g_free(counter->src_ip1);
+       FREE(counter->src_ip1);
        counter->src_iprange_type = NFACCT_IPRANGE_TYPE_NONE;
        return ret;
 }
@@ -196,7 +201,7 @@ static stc_error_e __del_iptables_tether_out(struct nfacct_rule *counter,
 
        ret = produce_net_rule(counter);
 
-       g_free(counter->dst_ip1);
+       FREE(counter->dst_ip1);
        counter->dst_iprange_type = NFACCT_IPRANGE_TYPE_NONE;
        return ret;
 }
@@ -515,16 +520,19 @@ 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)
+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;
+       char *ipaddr = NULL;
+       int ret;
 
-       STC_LOGI("add tether app (%s)", app_key->app_id);
+       STC_LOGI("add appid(%s) classid(%d)", app_key->app_id,
+                       app_value->classid);
 
        if (stc == NULL || connection == NULL)
                return FALSE;
@@ -550,9 +558,16 @@ static gboolean __add_application_monitor_for_tethering(gpointer key, gpointer v
        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);
+       /* get the ip address of the station based on its mac address */
+       ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
+       if (ret != STC_ERROR_NONE)
+               return FALSE;
+
+       /* tethering iptables rule */
+       __add_iptables_tether_in(&counter, ipaddr);
+       __add_iptables_tether_out(&counter, ipaddr);
 
+       g_free(ipaddr);
        return FALSE;
 }
 
@@ -564,8 +579,11 @@ static gboolean __remove_application_monitor_for_tethering(gpointer key, gpointe
        default_connection_s *connection = (default_connection_s *)data;
        stc_s *stc = stc_get_manager();
        struct nfacct_rule counter;
+       char *ipaddr = NULL;
+       int ret;
 
-       STC_LOGI("remove tether app (%s)", app_key->app_id);
+       STC_LOGI("remove appid(%s) classid(%d)", app_key->app_id,
+                       app_value->classid);
 
        if (stc == NULL || connection == NULL)
                return FALSE;
@@ -591,9 +609,15 @@ static gboolean __remove_application_monitor_for_tethering(gpointer key, gpointe
        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);
+       /* get the ip address of the station based on its mac address */
+       ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr);
+       if (ret != STC_ERROR_NONE)
+               return FALSE;
 
+       __del_iptables_tether_in(&counter, ipaddr);
+       __del_iptables_tether_out(&counter, ipaddr);
+
+       g_free(ipaddr);
        return FALSE;
 }
 
@@ -784,6 +808,96 @@ static void __add_iptables_rule(int64_t classid, nfacct_rule_intend intend,
        __add_ip6tables_out(&counter);
 }
 
+static void __add_tethering_iptables_rule(int64_t classid, gchar *mac,
+               nfacct_rule_intend intend, stc_iface_type_e iftype)
+{
+       default_connection_s *connection = stc_get_default_connection();
+       struct nfacct_rule counter;
+       stc_s *stc = stc_get_manager();
+       char *ipaddr = NULL;
+       int ret;
+
+       if (!stc || !mac)
+               return;
+
+       if (!stc->carg) {
+               stc->carg = MALLOC0(counter_arg_s, 1);
+               if (stc->carg == NULL)
+                       return;
+
+               stc->carg->sock = stc_monitor_get_counter_socket();
+       }
+
+       memset(&counter, 0, sizeof(struct nfacct_rule));
+
+       counter.carg = stc->carg;
+       counter.classid = classid;
+       counter.intend = intend;
+
+       if (connection->tether_state != TRUE ||
+               connection->tether_iface.ifname == NULL)
+       return;
+
+       counter.iftype = connection->tether_iface.type;
+       g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
+
+       /* get connected station ip based on its mac */
+       ret = stc_plugin_tether_get_station_ip(mac, &ipaddr);
+       if (ret != STC_ERROR_NONE)
+               return;
+
+       /* tethering iptables rule */
+       __add_iptables_tether_in(&counter, ipaddr);
+       __add_iptables_tether_out(&counter, ipaddr);
+       g_free(ipaddr);
+}
+
+static void __del_tethering_iptables_rule(int64_t classid, gchar *mac,
+               nfacct_rule_intend intend, stc_iface_type_e iftype)
+{
+       default_connection_s *connection = stc_get_default_connection();
+       struct nfacct_rule counter;
+       stc_s *stc = stc_get_manager();
+       char *ipaddr = NULL;
+       int ret;
+
+       if (!stc || !mac)
+               return;
+
+       if (!stc->carg) {
+               stc->carg = MALLOC0(counter_arg_s, 1);
+               if (stc->carg == NULL)
+                       return;
+
+               stc->carg->sock = stc_monitor_get_counter_socket();
+       }
+
+       memset(&counter, 0, sizeof(struct nfacct_rule));
+
+       counter.carg = stc->carg;
+       counter.classid = classid;
+       counter.intend = intend;
+
+       if (connection->tether_state != TRUE ||
+               connection->tether_iface.ifname == NULL)
+       return;
+
+       counter.iftype = connection->tether_iface.type;
+       g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
+
+       /* get connected station ip based on its mac */
+       ret = stc_plugin_tether_get_station_ip(mac, &ipaddr);
+       if (ret != STC_ERROR_NONE) {
+               STC_LOGE("Error: no IP found for station mac(%s)", mac);
+               return;
+       }
+
+       /* tethering iptables rule */
+       __del_iptables_tether_in(&counter, ipaddr);
+       __del_iptables_tether_out(&counter, ipaddr);
+       g_free(ipaddr);
+}
+
 static void __del_iptables_rule(int64_t classid, nfacct_rule_intend intend,
                                stc_iface_type_e iftype)
 {
@@ -872,6 +986,142 @@ static stc_cb_ret_e __statistics_info_cb(const table_statistics_info *info,
        return STC_CONTINUE;
 }
 
+static void __process_tethering_restriction(enum traffic_restriction_type rstn_type,
+               stc_rstn_key_s *rstn_key, stc_rstn_value_s *rstn_value, void *data)
+{
+       default_connection_s *old_connection = (default_connection_s *)data;
+       default_connection_s *connection = NULL;
+       char *mac_str = NULL;
+
+       if (old_connection != NULL)
+               connection = old_connection;
+       else
+               connection = stc_get_default_connection();
+
+       /* in case tethering is not active */
+       if (connection->tether_state == FALSE)
+               return;
+
+       /* rstn not applicable for this interface */
+       if (rstn_key->ifname != NULL && g_strcmp0("", rstn_key->ifname) != 0 &&
+                       (g_strcmp0(connection->tether_iface.ifname, rstn_key->ifname) != 0))
+               return;
+
+       /* in case appid not a tethering app */
+       if (!g_str_has_suffix(rstn_key->app_id, STC_TETHERING_APP_SUFFIX))
+               return;
+
+       /* Ignore TOTAL_TETHERING,
+        * Process only station appids */
+       if (rstn_value->classid == STC_TETHERING_APP_CLASSID)
+               return;
+
+       /* get the station mac based on classid */
+       stc_plugin_tether_get_station_by_classid(rstn_value->classid, &mac_str);
+       if (!mac_str) {
+               STC_LOGE("station not found for classid(%d)", rstn_value->classid);
+               return;
+       }
+
+       switch (rstn_type) {
+       case RST_SET:
+       {
+               int i;
+               table_counters_info info;
+               int64_t effective_limit[STC_RSTN_LIMIT_TYPE_MAX] = { 0, };
+
+                       memset(&info, 0, sizeof(table_counters_info));
+                       rstn_value->limit_exceeded = 0;
+
+                       if ((rstn_value->counter[STC_RSTN_LIMIT_TYPE_DATA] == 0 &&
+                                               rstn_value->limit[STC_RSTN_LIMIT_TYPE_DATA] >= 0) ||
+                                       (rstn_value->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] == 0 &&
+                                        rstn_value->limit[STC_RSTN_LIMIT_TYPE_DATA_WARN] >= 0) ||
+                                       (rstn_value->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] == 0 &&
+                                        rstn_value->limit[STC_RSTN_LIMIT_TYPE_MONTHLY] >= 0) ||
+                                       (rstn_value->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] == 0 &&
+                                        rstn_value->limit[STC_RSTN_LIMIT_TYPE_WEEKLY] >= 0) ||
+                                       (rstn_value->counter[STC_RSTN_LIMIT_TYPE_DAILY] == 0 &&
+                                        rstn_value->limit[STC_RSTN_LIMIT_TYPE_DAILY] >= 0)) {
+                               table_counters_get(rstn_value->restriction_id, &info);
+
+                               time_t current_time = 0;
+                               cumulative_data_s stat;
+                               table_statistics_select_rule rule;
+
+                               memset(&stat, 0, sizeof(cumulative_data_s));
+                               stat.month_start_ts = rstn_value->month_start_ts;
+                               stat.week_start_ts = g_system->last_week_ts;
+                               stat.day_start_ts = g_system->last_day_ts;
+
+                               memset(&rule, 0, sizeof(table_statistics_select_rule));
+                               rule.from = rstn_value->month_start_ts;
+                               time(&current_time);
+                               rule.to = current_time;
+                               rule.iftype = rstn_key->iftype;
+                               rule.granularity = GRANULARITY;
+
+                               table_statistics_per_app(rstn_key->app_id, &rule, __statistics_info_cb, &stat);
+
+                               rstn_value->counter[STC_RSTN_LIMIT_TYPE_DATA] = info.data_counter;
+                               rstn_value->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] = info.warn_counter;
+                               rstn_value->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] = info.monthly_counter + stat.monthly_stat;
+                               rstn_value->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] = info.weekly_counter + stat.weekly_stat;
+                               rstn_value->counter[STC_RSTN_LIMIT_TYPE_DAILY] = info.daily_counter + stat.daily_stat;
+                       }
+
+                       for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++) {
+                               if (rstn_value->limit[i] >= 0) {
+                                       effective_limit[i] = rstn_value->limit[i] - rstn_value->counter[i];
+
+                                       if (effective_limit[i] < 0)
+                                               rstn_value->limit_exceeded |= (1 << i);
+                               }
+                       }
+
+                       STC_LOGD("rstn_id [%llu], datausage [%llu] bytes",
+                                       rstn_value->restriction_id, info.data_counter);
+
+                       if (rstn_value->limit_exceeded != 0 &&
+                                       rstn_value->limit_exceeded != (1 << STC_RSTN_LIMIT_TYPE_DATA_WARN)) {
+                               __add_tethering_iptables_rule(rstn_value->classid, mac_str,
+                                               NFACCT_TETH_BLOCK, rstn_key->iftype);
+                       }
+
+                       rstn_value->rstn_state = STC_RSTN_STATE_ACTIVATED;
+       }
+       break;
+       case RST_EXCLUDE:
+       {
+               __add_tethering_iptables_rule(rstn_value->classid, mac_str,
+                                       NFACCT_TETH_ALLOW, rstn_key->iftype);
+
+                       rstn_value->rstn_state = STC_RSTN_STATE_ACTIVATED;
+                       rstn_value->limit_exceeded = 0;
+                       rstn_value->limit_notified = 0;
+       }
+       break;
+       case RST_UNSET:
+       {
+                       int i;
+                       __del_tethering_iptables_rule(rstn_value->classid, mac_str,
+                                       NFACCT_TETH_BLOCK, rstn_key->iftype);
+
+                       rstn_value->rstn_state = STC_RSTN_STATE_DEACTIVATED;
+                       rstn_value->limit_exceeded = 0;
+                       rstn_value->limit_notified = 0;
+
+                       for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++)
+                               if (rstn_value->limit[i] >= 0)
+                                       rstn_value->counter[i] = 0;
+       }
+       break;
+       default:
+                       ;//Do Nothing
+       }
+       FREE(mac_str);
+}
+
 static void __process_restriction(enum traffic_restriction_type rstn_type,
                                  stc_rstn_key_s *rstn_key,
                                  stc_rstn_value_s *rstn_value, void *data)
@@ -898,6 +1148,13 @@ static void __process_restriction(enum traffic_restriction_type rstn_type,
        if (rstn_value->classid <= STC_UNKNOWN_CLASSID)
                return;
 
+       /* Do not proceed for tethering station appid if found here,
+        * for tethering station apps __process_tethering_restriction() call
+        * will handle it */
+       if (g_str_has_suffix(rstn_key->app_id, STC_TETHERING_APP_SUFFIX) &&
+                       rstn_value->classid != STC_TETHERING_APP_CLASSID)
+               return;
+
        switch (rstn_type) {
        case RST_SET:
        {
@@ -1024,6 +1281,9 @@ static gboolean __remove_rstns_foreach_application(gpointer key,
        /* remove restriction from system */
        __process_restriction(RST_UNSET, rstn_key, rstn_value, NULL);
 
+       /* remove tethering restriction from system*/
+       __process_tethering_restriction(RST_UNSET, rstn_key, rstn_value, NULL);
+
        __print_rstn(rstn_key, rstn_value);
 out:
        return FALSE;
@@ -1125,6 +1385,36 @@ static stc_error_e __close_and_reopen_contr_sock(stc_system_s *system)
        return STC_ERROR_NONE;
 }
 
+static void __action_when_rstn_limit_exceeded_tethering(stc_rstn_key_s *rstn_key,
+               stc_rstn_value_s *rstn_value, classid_bytes_context_s *context)
+{
+       char *mac_str = NULL;
+       struct nfacct_rule *counter = context->counter;
+
+       /* get the station mac based on classid */
+       stc_plugin_tether_get_station_by_classid(counter->classid, &mac_str);
+       if (!mac_str) {
+               STC_LOGE("station not found for classid(%d)", counter->classid);
+               return;
+       }
+
+       STC_LOGI("station mac %s, classid %u, iftype %u, iotype %d, \
+                       intend %d, ifname %s, bytes %lld", mac_str,
+                       counter->classid, counter->iftype, counter->iotype,
+                       counter->intend, counter->ifname, context->bytes);
+
+       /* Block tethering station immediately */
+       counter->intend = NFACCT_TETH_BLOCK;
+       __del_tethering_iptables_rule(counter->classid, mac_str,
+                       NFACCT_TETH_BLOCK, rstn_key->iftype);
+
+       __add_tethering_iptables_rule(counter->classid, mac_str,
+                       NFACCT_TETH_BLOCK, rstn_key->iftype);
+       counter->intend = NFACCT_TETH_COUNTER;
+
+       g_free(mac_str);
+}
+
 static void __action_when_rstn_limit_exceeded(stc_rstn_limit_type_e limit_type,
                                                stc_rstn_key_s *rstn_key,
                                                stc_rstn_value_s *rstn_value,
@@ -1160,18 +1450,30 @@ static void __action_when_rstn_limit_exceeded(stc_rstn_limit_type_e limit_type,
                net_popup_content = "restriction threshold crossed";
                net_popup_type = "restriction_noti";
 
-               /* block immediately */
-               context->counter->intend = NFACCT_BLOCK;
-               __del_iptables_in(context->counter);
-               __del_iptables_out(context->counter);
-               __add_iptables_in(context->counter);
-               __add_iptables_out(context->counter);
+               /* Apply restriction for tethering apps if app_id is of tethering client
+                * otherwise do the normal iptables rule */
+               if (context->counter->intend == NFACCT_TETH_COUNTER) {
 
-               __del_ip6tables_in(context->counter);
-               __del_ip6tables_out(context->counter);
-               __add_ip6tables_in(context->counter);
-               __add_ip6tables_out(context->counter);
-               context->counter->intend = NFACCT_COUNTER;
+                       if (g_str_has_suffix(rstn_key->app_id, STC_TETHERING_APP_SUFFIX) &&
+                                       rstn_value->classid != STC_TETHERING_APP_CLASSID) {
+                               __action_when_rstn_limit_exceeded_tethering(rstn_key, rstn_value,
+                                               context);
+                       }
+
+               } else {
+                       /* block immediately */
+                       context->counter->intend = NFACCT_BLOCK;
+                       __del_iptables_in(context->counter);
+                       __del_iptables_out(context->counter);
+                       __add_iptables_in(context->counter);
+                       __add_iptables_out(context->counter);
+
+                       __del_ip6tables_in(context->counter);
+                       __del_ip6tables_out(context->counter);
+                       __add_ip6tables_in(context->counter);
+                       __add_ip6tables_out(context->counter);
+                       context->counter->intend = NFACCT_COUNTER;
+               }
 
                rstn_value->limit_exceeded |= (1 << limit_type);
 
@@ -1877,6 +2179,7 @@ static gboolean __remove_restriction(gpointer key, gpointer value,
        stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
 
        __process_restriction(RST_UNSET, rstn_key, rstn_value, data);
+       __process_tethering_restriction(RST_UNSET, rstn_key, rstn_value, data);
        __print_rstn(rstn_key, rstn_value);
        return FALSE;
 }
@@ -1891,10 +2194,13 @@ static gboolean __add_restriction_debug(gpointer key, gpointer value,
        if (rstn_value->rstn_state == STC_RSTN_STATE_ACTIVATED)
                return FALSE;
 
-       if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT)
+       if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) {
                __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
-       else
+               __process_tethering_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
+       } else {
                __process_restriction(RST_SET, rstn_key, rstn_value, data);
+               __process_tethering_restriction(RST_SET, rstn_key, rstn_value, data);
+       }
 
        __print_rstn(rstn_key, rstn_value);
 
@@ -1911,10 +2217,13 @@ static gboolean __add_restriction(gpointer key, gpointer value, gpointer data)
        if (rstn_value->rstn_state == STC_RSTN_STATE_ACTIVATED)
                return FALSE;
 
-       if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT)
+       if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) {
                __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
-       else
+               __process_tethering_restriction(RST_EXCLUDE, rstn_key, rstn_value, data);
+       } else {
                __process_restriction(RST_SET, rstn_key, rstn_value, data);
+               __process_tethering_restriction(RST_SET, rstn_key, rstn_value, data);
+       }
 
        return FALSE;
 }
@@ -1971,6 +2280,7 @@ static stc_error_e __rstn_tree_add(stc_rstn_key_s *key,
 
        rstn_key->app_id = g_strdup(key->app_id);
        rstn_key->ifname = g_strdup(key->ifname);
+       rstn_key->mac = g_strdup(key->mac);
        rstn_key->subscriber_id = g_strdup(key->subscriber_id);
        rstn_key->iftype = key->iftype;
        rstn_key->roaming = key->roaming;
@@ -2071,10 +2381,13 @@ static gboolean __add_rstn_foreach_application(gpointer key,
                goto out;
 
        /* add restriction to system */
-       if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT)
+       if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) {
                __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, NULL);
-       else
+               __process_tethering_restriction(RST_EXCLUDE, rstn_key, rstn_value, NULL);
+       } else {
                __process_restriction(RST_SET, rstn_key, rstn_value, NULL);
+               __process_tethering_restriction(RST_SET, rstn_key, rstn_value, NULL);
+       }
 
        __print_rstn(rstn_key, rstn_value);
 out:
@@ -2293,7 +2606,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);
+       g_strlcpy(value->mac, app_value.mac, MAC_ADDRESS_LEN);
 
        value->processes = g_tree_new_full(__processes_tree_key_compare, NULL,
                                           __processes_tree_key_free,
@@ -2302,6 +2615,11 @@ API stc_error_e stc_monitor_application_add(const stc_app_key_s app_key,
        /* create cgroup and update classid */
        value->classid = get_classid_by_app_id(app_key.app_id, TRUE);
 
+       /* update classid for tethering station based on its mac address */
+       if (g_str_has_suffix(app_key.app_id, STC_TETHERING_APP_SUFFIX) &&
+                               value->classid != STC_TETHERING_APP_CLASSID)
+               stc_plugin_tether_set_station_classid(value->mac, value->classid);
+
        g_tree_insert(g_system->apps, key, value);
 
        /* add nfacct rule for this classid */
@@ -2517,6 +2835,7 @@ stc_error_e stc_monitor_rstns_tree_add(const table_restrictions_info *info)
 
        key.app_id = g_strdup(info->app_id);
        key.ifname = g_strdup(info->ifname);
+       key.mac = g_strdup(info->mac);
        key.subscriber_id = g_strdup(info->subscriber_id);
        key.iftype = info->iftype;
        key.roaming = info->roaming;
@@ -2549,6 +2868,7 @@ stc_error_e stc_monitor_rstns_tree_add(const table_restrictions_info *info)
 
        FREE(key.app_id);
        FREE(key.ifname);
+       FREE(key.mac);
        FREE(key.subscriber_id);
        return ret;
 }
index 1813e40..afb170d 100644 (file)
@@ -65,3 +65,69 @@ int stc_plugin_tether_deinit(void)
        __STC_LOG_FUNC_EXIT__;
        return STC_ERROR_NONE;
 }
+
+int stc_plugin_tether_get_station_ip(const char *mac, char **ipaddr)
+{
+       __STC_LOG_FUNC_ENTER__;
+       char ip[INET_ADDRSTRLEN+1];
+
+       if (!stc_tether_plugin_enabled ||
+                       mac == NULL || ipaddr == NULL) {
+               STC_LOGE("invalid args");
+               __STC_LOG_FUNC_EXIT__;
+               return STC_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(ip, 0, sizeof(ip));
+
+       if (plugin->get_station_ip(mac, ip) != STC_ERROR_NONE)
+               return STC_ERROR_FAIL;
+
+       *ipaddr = g_strdup(ip);
+       STC_LOGI("station ip(%s)", *ipaddr);
+
+       __STC_LOG_FUNC_EXIT__;
+       return STC_ERROR_NONE;
+}
+
+int stc_plugin_tether_get_station_by_classid(const int classid, char **mac)
+{
+       __STC_LOG_FUNC_ENTER__;
+       char mac_addr[STATION_MAC_STR_LEN+1];
+
+       if (!stc_tether_plugin_enabled || mac == NULL) {
+               STC_LOGE("invalid args");
+               __STC_LOG_FUNC_EXIT__;
+               return STC_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(mac_addr, 0, sizeof(mac_addr));
+
+       if (plugin->get_station_by_classid(classid, mac_addr) != STC_ERROR_NONE)
+               return STC_ERROR_FAIL;
+
+       *mac = g_strdup(mac_addr);
+       STC_LOGI("station mac(%s)", *mac);
+
+       __STC_LOG_FUNC_EXIT__;
+       return STC_ERROR_NONE;
+}
+
+int stc_plugin_tether_set_station_classid(const char *mac, int classid)
+{
+       __STC_LOG_FUNC_ENTER__;
+
+       if (!stc_tether_plugin_enabled || mac == NULL) {
+               STC_LOGE("invalid args");
+               __STC_LOG_FUNC_EXIT__;
+               return STC_ERROR_INVALID_PARAMETER;
+       }
+
+       if (plugin->set_station_classid(mac, classid) != STC_ERROR_NONE)
+               return STC_ERROR_FAIL;
+
+       STC_LOGI("classid(%d) for station mac(%s) is set successfully",
+                       classid, mac);
+       __STC_LOG_FUNC_EXIT__;
+       return STC_ERROR_NONE;
+}
index 2f44459..f4cd753 100644 (file)
@@ -241,6 +241,12 @@ static void __stc_extract_restriction_rule(const char *key, GVariant *value,
                rule->rstn_type = g_variant_get_uint16(value);
                STC_LOGD("type: [%u]", (unsigned int) rule->rstn_type);
 
+       } else if (!g_strcmp0(key, "mac")) {
+               guint str_length;
+               const gchar *str = g_variant_get_string(value, &str_length);
+               rule->mac = g_strdup(str);
+               STC_LOGD("mac: [%s]", rule->mac);
+
        } else {
                STC_LOGD("Unknown select rule"); //LCOV_EXCL_LINE
        }