Add support for Tethering data monitoring and data restriction rules 19/177919/9 accepted/tizen/unified/20180515.163358 submit/tizen/20180511.091455 submit/tizen/20180514.105807
authorMilind Murhekar <m.murhekar@samsung.com>
Fri, 4 May 2018 10:18:28 +0000 (15:48 +0530)
committerMilind Murhekar <m.murhekar@samsung.com>
Thu, 10 May 2018 09:21:25 +0000 (14:51 +0530)
Description: This patch applies the tethering interface
monitoring, when Hotspot is enabled/disabled, Also
it supports data restriction rules for tethering interface
including default network connection.

Change-Id: I2b79de433abde7b5ae46d1fb9d7b537975398dab
Signed-off-by: Milind Murhekar <m.murhekar@samsung.com>
include/stc-manager.h
packaging/stc-manager.spec
src/helper/helper-net-cls.c
src/monitor/include/stc-default-connection.h
src/monitor/stc-default-connection.c
src/monitor/stc-monitor.c

index f43c92d..14d5cc6 100755 (executable)
@@ -30,6 +30,7 @@
 #define STC_TOTAL_BLUETOOTH "TOTAL_BLUETOOTH"
 #define STC_TOTAL_IPV4 "TOTAL_IPV4"
 #define STC_TOTAL_IPV6 "TOTAL_IPV6"
+#define STC_TOTAL_TETHERING "TOTAL_TETHERING"
 
 #define STC_IPTABLES "/usr/sbin/iptables"
 #define STC_IP6TABLES "/usr/sbin/ip6tables"
@@ -158,6 +159,8 @@ typedef enum {
        STC_IFACE_BLUETOOTH,  /**< bluetooth interface */
        STC_IFACE_IPV4,       /**< ipv4 interface */
        STC_IFACE_IPV6,       /**< ipv6 interface */
+       STC_IFACE_USB,        /**< usb interface */
+       STC_IFACE_P2P,        /**< p2p interface */
        STC_IFACE_ALL,        /**< enumerate all network interface types */
        STC_IFACE_LAST_ELEM
 } stc_iface_type_e;
index 95ff39a..bb6a9c1 100644 (file)
@@ -1,6 +1,6 @@
 Name:       stc-manager
 Summary:    STC(Smart Traffic Control) manager
-Version:    0.0.61
+Version:    0.0.63
 Release:    0
 Group:      Network & Connectivity/Other
 License:    Apache-2.0
index c1460dc..e13c729 100755 (executable)
@@ -132,6 +132,9 @@ uint32_t get_classid_by_app_id(const char *app_id, int create)
        if (!strcmp(app_id, STC_TOTAL_IPV6))
                return STC_TOTAL_IPV6_CLASSID;
 
+       if (!strcmp(app_id, STC_TOTAL_TETHERING))
+               return STC_TETHERING_APP_CLASSID;
+
        if (strstr(app_id, STC_BACKGROUND_APP_SUFFIX))
                path_to_net_cgroup_dir = BACKGROUND_CGROUP_NETWORK;
        else
index 230671b..222e77b 100755 (executable)
 #define IMSI_LENGTH 16
 #define SHA256_DIGEST_LENGTH 32
 
+#define TETHERING_USB_IF   "usb0"
+#define TETHERING_WIFI_IF  "wlan0"
+#define TETHERING_BT_IF    "bnep0"
+#define TETHERING_P2P_IF   "p2p0"
+
+/**
+ * @brief Tethering interface info
+ */
+typedef struct {
+       gchar *ifname;
+       stc_iface_type_e type;
+} tether_iface_s;
+
 /**
  * @brief default connection information will be fetched from net-config
  */
@@ -44,6 +57,12 @@ typedef struct {
 
        /* hardware network protocol type */
        stc_hw_net_protocol_type_e hw_net_protocol_type;
+
+       /* tethering status */
+       gboolean tether_state;
+
+       /* tethering interface */
+       tether_iface_s tether_iface;
 } default_connection_s;
 
 stc_error_e stc_default_connection_monitor_init(stc_s *stc);
index 9a359d4..244a8b9 100755 (executable)
@@ -193,12 +193,24 @@ static void __print_default_connection_info(void)
        STC_LOGI("==================================================");
 }
 
+static void __print_tether_connection_info(void)
+{
+       STC_LOGI("============= tethering connection info ============");
+       STC_LOGI("mode    [%u]", g_default_connection.tether_state ? TRUE : FALSE);
+       STC_LOGI("type    [%d]", g_default_connection.tether_iface.type);
+       STC_LOGI("ifname  [%s]", g_default_connection.tether_iface.ifname);
+       STC_LOGI("====================================================");
+}
+
 static void __reset_default_connection_data(void)
 {
        FREE(g_default_connection.path);
        FREE(g_default_connection.ifname);
+       FREE(g_default_connection.tether_iface.ifname);
        g_default_connection.type = STC_IFACE_UNKNOWN;
        g_default_connection.roaming = FALSE;
+       g_default_connection.tether_iface.type = STC_IFACE_UNKNOWN;
+       g_default_connection.tether_state = FALSE;
 }
 
 static gboolean __is_cellular_internet_profile(const char *profile)
@@ -482,8 +494,80 @@ done:
        return;
 }
 
+static void __vconf_key_callback(keynode_t *node, void *user_data)
+{
+       int vconf_key;
+
+       if (node == NULL) {
+               STC_LOGE("Invalid parameter");
+               return;
+       }
+
+       if (vconf_keynode_get_type(node) != VCONF_TYPE_INT) {
+               STC_LOGE("Invalid vconf key type");
+               return;
+       }
+
+       vconf_key = vconf_keynode_get_int(node);
+
+       /* Check the tethering type */
+       switch (vconf_key) {
+       case VCONFKEY_MOBILE_HOTSPOT_MODE_USB:
+               STC_LOGI("Hotspot mode USB type !");
+               g_default_connection.tether_state = TRUE;
+               g_default_connection.tether_iface.ifname = g_strdup(TETHERING_USB_IF);
+               g_default_connection.tether_iface.type = STC_IFACE_USB;
+               break;
+       case VCONFKEY_MOBILE_HOTSPOT_MODE_WIFI:
+               STC_LOGI("Hotspot mode Wi-Fi type !");
+               g_default_connection.tether_state = TRUE;
+               g_default_connection.tether_iface.ifname = g_strdup(TETHERING_WIFI_IF);
+               g_default_connection.tether_iface.type = STC_IFACE_WIFI;
+               break;
+       case VCONFKEY_MOBILE_HOTSPOT_MODE_BT:
+               STC_LOGI("Hotspot mode Bluetooth type !");
+               g_default_connection.tether_state = TRUE;
+               g_default_connection.tether_iface.ifname = g_strdup(TETHERING_BT_IF);
+               g_default_connection.tether_iface.type = STC_IFACE_BLUETOOTH;
+               break;
+       case VCONFKEY_MOBILE_HOTSPOT_MODE_P2P:
+               STC_LOGI("Hotspot mode P2P type !");
+               g_default_connection.tether_state = TRUE;
+               g_default_connection.tether_iface.ifname = g_strdup(TETHERING_P2P_IF);
+               g_default_connection.tether_iface.type = STC_IFACE_P2P;
+               break;
+       case VCONFKEY_MOBILE_HOTSPOT_MODE_NONE:
+               STC_LOGI("Hotspot mode none");
+               g_default_connection.tether_state = FALSE;
+               break;
+       default:
+               STC_LOGE("Unknown Hotspot mode type !");
+               break;
+       }
+
+       /* add monitoring for tethering if active found */
+       if (g_default_connection.tether_state == TRUE && g_default_connection.tether_iface.ifname) {
+               __print_tether_connection_info();
+               stc_monitor_update_rstn_by_default_connection(&g_default_connection);
+               stc_firewall_update();
+               STC_LOGI("Data monitoring started for tethering iface !");
+               return;
+       }
+
+       /* remove monitoring for tethering if in-active found */
+       if (g_default_connection.tether_state == FALSE && g_default_connection.tether_iface.ifname) {
+               stc_monitor_update_rstn_by_default_connection(&g_default_connection);
+               g_free(g_default_connection.tether_iface.ifname);
+               g_default_connection.tether_iface.ifname = NULL;
+               g_default_connection.tether_iface.type = STC_IFACE_UNKNOWN;
+               STC_LOGI("Data monitoring stopped for tethering iface !");
+               return;
+       }
+}
+
 stc_error_e stc_default_connection_monitor_init(stc_s *stc)
 {
+       int ret;
        ret_value_msg_if(stc == NULL, STC_ERROR_INVALID_PARAMETER, "failed to get stc data");
 
        __get_default_profile(stc->connection);
@@ -497,6 +581,10 @@ stc_error_e stc_default_connection_monitor_init(stc_s *stc)
                                                   _service_signal_cb,
                                                   NULL, NULL);
 
+       ret = vconf_notify_key_changed(VCONFKEY_MOBILE_HOTSPOT_MODE, __vconf_key_callback, NULL);
+       if (ret < 0)
+               STC_LOGE("vconf_notify_key_changed failed: %d", ret);
+
        STC_LOGI("Successfully subscribed connman [%s] signal", CONNMAN_SIGNAL_PROPERTY_CHANGED);
        return STC_ERROR_NONE;
 }
index b73a889..62a0c20 100755 (executable)
@@ -403,8 +403,16 @@ static gboolean __add_application_monitor(gpointer key, gpointer value,
                counter.carg = stc->carg;
                counter.classid = app_value->classid;
                counter.intend = NFACCT_COUNTER;
-               counter.iftype = connection->type;
-               g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
+
+               if (connection->tether_state == TRUE &&
+                       connection->tether_iface.ifname != NULL &&
+                       app_value->classid == STC_TETHERING_APP_CLASSID) {
+                       counter.iftype = connection->tether_iface.type;
+                       g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
+               } else {
+                       counter.iftype = connection->type;
+                       g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
+               }
 
                if (app_value->classid == STC_TOTAL_IPV4_CLASSID) {
                        __add_iptables_in(&counter);
@@ -446,8 +454,16 @@ static gboolean __remove_application_monitor(gpointer key, gpointer value,
                counter.carg = stc->carg;
                counter.classid = app_value->classid;
                counter.intend = NFACCT_COUNTER;
-               counter.iftype = connection->type;
-               g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
+
+               if (connection->tether_state == FALSE &&
+                       connection->tether_iface.ifname != NULL &&
+                       app_value->classid == STC_TETHERING_APP_CLASSID) {
+                       counter.iftype = connection->tether_iface.type;
+                       g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
+               } else {
+                       counter.iftype = connection->type;
+                       g_strlcpy(counter.ifname, connection->ifname, MAX_IFACE_LENGTH);
+               }
 
                __del_iptables_in(&counter);
                __del_iptables_out(&counter);
@@ -480,6 +496,7 @@ static void __add_iptables_rule(int64_t classid, nfacct_rule_intend intend,
                                stc_iface_type_e iftype)
 {
        char *default_ifname = stc_default_connection_get_ifname();
+       default_connection_s *connection = stc_get_default_connection();
        struct nfacct_rule counter;
        stc_s *stc = stc_get_manager();
        if (!stc) {
@@ -500,8 +517,16 @@ static void __add_iptables_rule(int64_t classid, nfacct_rule_intend intend,
        counter.carg = stc->carg;
        counter.classid = classid;
        counter.intend = intend;
-       counter.iftype = iftype;
-       g_strlcpy(counter.ifname, default_ifname, MAX_IFACE_LENGTH);
+
+       if (connection && connection->tether_iface.ifname != NULL &&
+               classid == STC_TETHERING_APP_CLASSID) {
+               counter.iftype = connection->tether_iface.type;
+               g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
+       } else {
+               counter.iftype = iftype;
+               g_strlcpy(counter.ifname, default_ifname, MAX_IFACE_LENGTH);
+       }
+
        g_free(default_ifname);
 
        /* iptables rule */
@@ -517,6 +542,7 @@ static void __del_iptables_rule(int64_t classid, nfacct_rule_intend intend,
                                stc_iface_type_e iftype)
 {
        char *default_ifname = stc_default_connection_get_ifname();
+       default_connection_s *connection = stc_get_default_connection();
        struct nfacct_rule counter;
        stc_s *stc = stc_get_manager();
        if (!stc) {
@@ -537,8 +563,16 @@ static void __del_iptables_rule(int64_t classid, nfacct_rule_intend intend,
        counter.carg = stc->carg;
        counter.classid = classid;
        counter.intend = intend;
-       counter.iftype = iftype;
-       g_strlcpy(counter.ifname, default_ifname, MAX_IFACE_LENGTH);
+
+       if (connection && connection->tether_iface.ifname != NULL &&
+               classid == STC_TETHERING_APP_CLASSID) {
+               counter.iftype = connection->tether_iface.type;
+               g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH);
+       } else {
+               counter.iftype = iftype;
+               g_strlcpy(counter.ifname, default_ifname, MAX_IFACE_LENGTH);
+       }
+
        g_free(default_ifname);
 
        /* iptables rule */
@@ -569,7 +603,8 @@ static void __process_restriction(enum traffic_restriction_type rstn_type,
 
        /* rstn not applicable for this interface */
        if (rstn_key->ifname != NULL && g_strcmp0("", rstn_key->ifname) != 0 &&
-           g_strcmp0(connection->ifname, rstn_key->ifname) != 0)
+           (g_strcmp0(connection->ifname, rstn_key->ifname) != 0) &&
+               (g_strcmp0(connection->tether_iface.ifname, rstn_key->ifname) != 0))
                return;
 
        /* classid is invalid */
@@ -622,8 +657,12 @@ static void __process_restriction(enum traffic_restriction_type rstn_type,
                rstn_value->data_limit_reached = TRUE;
                break;
        case RST_UNSET:
-               __del_iptables_rule(rstn_value->classid, rstn_value->rstn_type,
-                                   rstn_key->iftype);
+               if (rstn_value->classid == STC_TETHERING_APP_CLASSID)
+                       __del_iptables_rule(rstn_value->classid, NFACCT_BLOCK,
+                                           rstn_key->iftype);
+               else
+                       __del_iptables_rule(rstn_value->classid, rstn_value->rstn_type,
+                                           rstn_key->iftype);
 
                rstn_value->rstn_state = STC_RSTN_STATE_DEACTIVATED;
                rstn_value->data_limit_reached = FALSE;
@@ -848,11 +887,19 @@ static gboolean __interface_rstn_counter_update(stc_rstn_key_s *rstn_key,
                                                classid_bytes_context_s *context)
 {
        if ((rstn_value->classid == STC_TOTAL_DATACALL_CLASSID &&
-            context->counter->iftype == STC_IFACE_DATACALL) ||
-           (rstn_value->classid == STC_TOTAL_WIFI_CLASSID &&
-            context->counter->iftype == STC_IFACE_WIFI) ||
-           (rstn_value->classid == STC_TOTAL_BLUETOOTH_CLASSID &&
-            context->counter->iftype == STC_IFACE_BLUETOOTH)) {
+               context->counter->iftype == STC_IFACE_DATACALL) ||
+               (rstn_value->classid == STC_TOTAL_WIFI_CLASSID &&
+               context->counter->iftype == STC_IFACE_WIFI) ||
+               (rstn_value->classid == STC_TOTAL_BLUETOOTH_CLASSID &&
+               context->counter->iftype == STC_IFACE_BLUETOOTH) ||
+               (rstn_value->classid == STC_TETHERING_APP_CLASSID &&
+                context->counter->iftype == STC_IFACE_WIFI) ||
+               (rstn_value->classid == STC_TETHERING_APP_CLASSID &&
+                context->counter->iftype == STC_IFACE_BLUETOOTH) ||
+               (rstn_value->classid == STC_TETHERING_APP_CLASSID &&
+                context->counter->iftype == STC_IFACE_USB) ||
+               (rstn_value->classid == STC_TETHERING_APP_CLASSID &&
+                context->counter->iftype == STC_IFACE_P2P)) {
                context->counter->classid = rstn_value->classid;
                return __rstn_counter_update(rstn_key, rstn_value, context);
        }
@@ -905,16 +952,40 @@ static gboolean __update_app_statistics(gpointer key, gpointer value,
        memset(&stat_key, 0, sizeof(stc_db_classid_iftype_key));
        memset(&stat, 0 , sizeof(stc_db_app_stats));
 
+       /* Do not update statistics for Tethering
+        * if tethering is in-active found */
+       if (default_connection &&
+               default_connection->tether_state == FALSE &&
+               !strcmp(app_key->app_id, STC_TOTAL_TETHERING))
+               return FALSE;
+
+       /* Do not update statistics for Wi-Fi
+        * if tethering is active on wlan0 iface */
+       if (default_connection && default_connection->tether_state &&
+               default_connection->tether_iface.type == STC_IFACE_WIFI &&
+               !strcmp(app_key->app_id, STC_TOTAL_WIFI))
+               return FALSE;
+
        stat_key.classid = app_value->classid;
-       stat_key.iftype = default_connection->type;
+
+       if (app_value->classid == STC_TETHERING_APP_CLASSID &&
+               default_connection->tether_state == TRUE)
+               stat_key.iftype = default_connection->tether_iface.type;
+       else
+               stat_key.iftype = default_connection->type;
 
        if (STC_IFACE_DATACALL == stat_key.iftype)
                stat_key.subscriber_id = g_strdup(default_connection->subscriber_id);
        else
                stat_key.subscriber_id = g_strdup("none_subid"); //LCOV_EXCL_LINE
 
-       g_strlcpy(stat_key.ifname, default_connection->ifname,
-                 MAX_IFACE_LENGTH);
+       if (app_value->classid == STC_TETHERING_APP_CLASSID &&
+               default_connection->tether_state == TRUE)
+               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);
 
        stat.app_id = g_strdup(app_key->app_id);
        stat.snd_count = app_value->counter.out_bytes;
@@ -1028,7 +1099,15 @@ static void __interface_counter_update(stc_app_key_s *app_key,
            (app_value->classid == STC_TOTAL_WIFI_CLASSID &&
             context->counter->iftype == STC_IFACE_WIFI) ||
            (app_value->classid == STC_TOTAL_BLUETOOTH_CLASSID &&
-            context->counter->iftype == STC_IFACE_BLUETOOTH))
+            context->counter->iftype == STC_IFACE_BLUETOOTH) ||
+               (app_value->classid == STC_TETHERING_APP_CLASSID &&
+                context->counter->iftype == STC_IFACE_WIFI) ||
+               (app_value->classid == STC_TETHERING_APP_CLASSID &&
+                context->counter->iftype == STC_IFACE_BLUETOOTH) ||
+               (app_value->classid == STC_TETHERING_APP_CLASSID &&
+                context->counter->iftype == STC_IFACE_USB) ||
+               (app_value->classid == STC_TETHERING_APP_CLASSID &&
+                context->counter->iftype == STC_IFACE_P2P))
                __app_counter_update(app_key, app_value, context);
 }
 
@@ -1617,6 +1696,7 @@ stc_error_e stc_monitor_init(void)
        __add_application_by_interface(STC_TOTAL_BLUETOOTH);
        __add_application_by_interface(STC_TOTAL_IPV4);
        __add_application_by_interface(STC_TOTAL_IPV6);
+       __add_application_by_interface(STC_TOTAL_TETHERING);
 
        /* creating restriction rules tree */
        __update_contr_cb(NULL);
@@ -1855,8 +1935,11 @@ void stc_monitor_update_rstn_by_default_connection(void *data)
 
        FREE(old_connection.path);
        FREE(old_connection.ifname);
+       FREE(old_connection.tether_iface.ifname);
        old_connection.type = 0;
        old_connection.roaming = 0;
+       old_connection.tether_state = FALSE;
+       old_connection.tether_iface.type = 0;
 
        if (new_connection != NULL && new_connection->path != NULL) {
                if (g_system->apps)
@@ -1870,8 +1953,11 @@ void stc_monitor_update_rstn_by_default_connection(void *data)
 
                old_connection.path = g_strdup(new_connection->path);
                old_connection.ifname = g_strdup(new_connection->ifname);
+               old_connection.tether_iface.ifname = g_strdup(new_connection->tether_iface.ifname);
                old_connection.type = new_connection->type;
                old_connection.roaming = new_connection->roaming;
+               old_connection.tether_state = new_connection->tether_state;
+               old_connection.tether_iface.type = new_connection->tether_iface.type;
        }
 }