+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vconf.h>
+#include <vconf-keys.h>
+
+#include "counter.h"
+#include "stc-monitor.h"
+#include "stc-monitor-rstn.h"
+#include "stc-monitor-ipt.h"
+#include "stc-time.h"
+#include "table-counters.h"
+#include "table-restrictions.h"
+#include "table-statistics.h"
+#include "helper-net-cls.h"
+#include "stc-manager-plugin-appstatus.h"
+#include "stc-manager-plugin-tether.h"
+
+static void __print_rstn(stc_rstn_data_s *rstn_data)
+{
+ STC_LOGI("RstnID[%llu] AppID[%s] classid[%u] "
+ "iftype[%d] ifname[%s] rstn_state[%d] "
+ "rstn_type[%d] roaming[%d] subscriber_id[%s]",
+ rstn_data->restriction_id,
+ rstn_data->app_id, rstn_data->classid,
+ rstn_data->iftype, rstn_data->ifname,
+ rstn_data->rstn_state, rstn_data->rstn_type,
+ rstn_data->roaming, rstn_data->subscriber_id);
+ STC_LOGI("month_start_date[%d] limit[%lld] "
+ "warn_limit[%lld] monthly_limit[%lld] "
+ "weekly_limit[%lld] daily_limit[%lld] ",
+ rstn_data->month_start_date,
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA],
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA_WARN],
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_MONTHLY],
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_WEEKLY],
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DAILY]);
+ STC_LOGI("data_counter[%lld] warn_counter[%lld] "
+ "monthly_counter[%lld] weekly_counter[%lld] "
+ "daily_counter[%lld]",
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA],
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN],
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY],
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY],
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY]);
+}
+
+static int __vconf_get_int(const char *key, int *value)
+{
+ int ret = 0;
+
+ ret = vconf_get_int(key, value);
+ if (ret != VCONF_OK) {
+ STC_LOGE("Failed to get vconfkey [%s] value", key);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __vconf_set_int(const char *key, int value)
+{
+ int ret = 0;
+
+ ret = vconf_set_int(key, value);
+ if (ret != VCONF_OK) {
+ STC_LOGE("Failed to set vconfkey [%s] value", key);
+ return -1;
+ }
+
+ return 0;
+}
+
+static stc_cb_ret_e __statistics_info_cb(const table_statistics_info *info,
+ void *user_data)
+{
+ stc_rstn_cumulative_data_s *stat = (stc_rstn_cumulative_data_s *)user_data;
+ int64_t counters = 0;
+
+ counters = info->cnt.in_bytes + info->cnt.out_bytes;
+
+ stat->monthly_stat += counters;
+ if (stat->week_start_ts <= info->interval->from)
+ stat->weekly_stat += counters;
+ if (stat->day_start_ts <= info->interval->from)
+ stat->daily_stat += counters;
+
+ return STC_CONTINUE;
+}
+
+static void __rstn_add_tether_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_contr_sock();
+ }
+
+ 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 */
+ stc_monitor_tether_add_in(&counter, ipaddr);
+ stc_monitor_tether_add_out(&counter, ipaddr);
+ g_free(ipaddr);
+}
+
+static void __rstn_del_tether_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_contr_sock();
+ }
+
+ 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 */
+ stc_monitor_tether_del_in(&counter, ipaddr);
+ stc_monitor_tether_del_out(&counter, ipaddr);
+ g_free(ipaddr);
+}
+
+static void __rstn_add_ipt_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) {
+ g_free(default_ifname);
+ return;
+ }
+
+ if (!stc->carg) {
+ stc->carg = MALLOC0(counter_arg_s, 1);
+ if (stc->carg == NULL) {
+ g_free(default_ifname);
+ return;
+ }
+
+ stc->carg->sock = stc_monitor_get_contr_sock();
+ }
+
+ memset(&counter, 0, sizeof(struct nfacct_rule));
+
+ counter.carg = stc->carg;
+ counter.classid = classid;
+ counter.intend = intend;
+
+ 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 */
+ stc_monitor_ipt_add_in(&counter);
+ stc_monitor_ipt_add_out(&counter);
+
+ /* ip6tables rule */
+ stc_monitor_ip6t_add_in(&counter);
+ stc_monitor_ip6t_add_out(&counter);
+}
+
+static void __rstn_del_ipt_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) {
+ g_free(default_ifname);
+ return;
+ }
+
+ if (!stc->carg) {
+ stc->carg = MALLOC0(counter_arg_s, 1);
+ if (stc->carg == NULL) {
+ g_free(default_ifname);
+ return;
+ }
+
+ stc->carg->sock = stc_monitor_get_contr_sock();
+ }
+
+ memset(&counter, 0, sizeof(struct nfacct_rule));
+
+ counter.carg = stc->carg;
+ counter.classid = classid;
+ counter.intend = intend;
+
+ 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 */
+ stc_monitor_ipt_del_in(&counter);
+ stc_monitor_ipt_del_out(&counter);
+
+ /* ip6tables rule */
+ stc_monitor_ip6t_del_in(&counter);
+ stc_monitor_ip6t_del_out(&counter);
+}
+
+static void __rstn_set_noti_state(int value)
+{
+ int state = STC_RSTN_STATE_INIT;
+
+ if (__vconf_get_int(VCONFKEY_SETAPPL_DATA_RESTRICTION_INT, &state))
+ return;
+
+ if (state == value) {
+ STC_LOGI("No need to change a restriction status: %d", state);
+ return;
+ }
+
+ __vconf_set_int(VCONFKEY_SETAPPL_DATA_RESTRICTION_INT, value);
+}
+
+static void __rstn_tethering_process(enum traffic_restriction_type rstn_type,
+ char *app_id, stc_rstn_data_s *rstn_data, 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_data->ifname != NULL && g_strcmp0("", rstn_data->ifname) != 0 &&
+ (g_strcmp0(connection->tether_iface.ifname, rstn_data->ifname) != 0))
+ return;
+
+ /* in case appid not a tethering app */
+ if (!g_str_has_suffix(app_id, STC_TETHERING_APP_SUFFIX))
+ return;
+
+ /* Ignore TOTAL_TETHERING,
+ * Process only station appids */
+ if (rstn_data->classid == STC_TETHERING_APP_CLASSID)
+ return;
+
+ /* get the station mac based on classid */
+ stc_plugin_tether_get_station_by_classid(rstn_data->classid, &mac_str);
+ if (!mac_str) {
+ STC_LOGE("Station not found for classid(%d)", rstn_data->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_data->limit_exceeded = 0;
+
+ if ((rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA_WARN] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_MONTHLY] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_WEEKLY] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DAILY] >= 0)) {
+ table_counters_get(rstn_data->restriction_id, &info);
+
+ time_t current_time = 0;
+ stc_rstn_cumulative_data_s stat;
+ table_statistics_select_rule rule;
+ time_t last_week_ts = stc_monitor_get_last_week_ts();
+ time_t last_day_ts = stc_monitor_get_last_day_ts();
+
+ memset(&stat, 0, sizeof(stc_rstn_cumulative_data_s));
+ stat.month_start_ts = rstn_data->month_start_ts;
+ stat.week_start_ts = last_week_ts;
+ stat.day_start_ts = last_day_ts;
+
+ memset(&rule, 0, sizeof(table_statistics_select_rule));
+ rule.from = rstn_data->month_start_ts;
+ time(¤t_time);
+ rule.to = current_time;
+ rule.iftype = rstn_data->iftype;
+ rule.granularity = GRANULARITY;
+
+ table_statistics_per_app(app_id, &rule, __statistics_info_cb, &stat);
+
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA] = info.data_counter;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] = info.warn_counter;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] = info.monthly_counter + stat.monthly_stat;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] = info.weekly_counter + stat.weekly_stat;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY] = info.daily_counter + stat.daily_stat;
+ }
+
+ for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++) {
+ if (rstn_data->limit[i] >= 0) {
+ effective_limit[i] = rstn_data->limit[i] - rstn_data->counter[i];
+
+ if (effective_limit[i] < 0)
+ rstn_data->limit_exceeded |= (1 << i);
+ }
+ }
+
+ STC_LOGD("Rstn_id[%llu] datausage[%lld]bytes",
+ rstn_data->restriction_id, info.data_counter);
+
+ if (rstn_data->limit_exceeded != 0 &&
+ rstn_data->limit_exceeded != (1 << STC_RSTN_LIMIT_TYPE_DATA_WARN)) {
+ __rstn_add_tether_rule(rstn_data->classid, mac_str,
+ NFACCT_TETH_BLOCK, rstn_data->iftype);
+ }
+
+ rstn_data->rstn_state = STC_RSTN_STATE_ACTIVATED;
+ }
+ break;
+ case RST_EXCLUDE:
+ {
+ __rstn_add_tether_rule(rstn_data->classid, mac_str,
+ NFACCT_TETH_ALLOW, rstn_data->iftype);
+
+ rstn_data->rstn_state = STC_RSTN_STATE_ACTIVATED;
+ rstn_data->limit_exceeded = 0;
+ rstn_data->limit_notified = 0;
+ }
+ break;
+ case RST_UNSET:
+ {
+ int i;
+ __rstn_del_tether_rule(rstn_data->classid, mac_str,
+ NFACCT_TETH_BLOCK, rstn_data->iftype);
+
+ rstn_data->rstn_state = STC_RSTN_STATE_DEACTIVATED;
+ rstn_data->limit_exceeded = 0;
+ rstn_data->limit_notified = 0;
+
+ for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++)
+ if (rstn_data->limit[i] >= 0)
+ rstn_data->counter[i] = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ FREE(mac_str);
+}
+
+static void __rstn_process(enum traffic_restriction_type rstn_type,
+ char *app_id, stc_rstn_data_s *rstn_data, void *data)
+{
+ default_connection_s *old_connection = (default_connection_s *)data;
+ default_connection_s *connection = NULL;
+
+ if (old_connection != NULL)
+ connection = old_connection;
+ else
+ connection = stc_get_default_connection();
+
+ /* no default ifname */
+ if (connection->ifname == NULL)
+ return;
+
+ /* rstn not applicable for this interface */
+ if (rstn_data->ifname != NULL &&
+ g_strcmp0(rstn_data->ifname, "") != 0 &&
+ (g_strcmp0(connection->ifname, rstn_data->ifname) != 0) &&
+ (g_strcmp0(connection->tether_iface.ifname, rstn_data->ifname) != 0))
+ return;
+
+ /* classid is invalid */
+ if (rstn_data->classid <= STC_UNKNOWN_CLASSID)
+ return;
+
+ /* Do not proceed for tethering station appid if found here,
+ * for tethering station apps __rstn_tethering_process() call
+ * will handle it */
+ if (g_str_has_suffix(app_id, STC_TETHERING_APP_SUFFIX) &&
+ rstn_data->classid != STC_TETHERING_APP_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_data->limit_exceeded = 0;
+
+ if ((rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA_WARN] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_MONTHLY] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_WEEKLY] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DAILY] >= 0)) {
+ table_counters_get(rstn_data->restriction_id, &info);
+
+ time_t current_time = 0;
+ stc_rstn_cumulative_data_s stat;
+ table_statistics_select_rule rule;
+ time_t last_week_ts = stc_monitor_get_last_week_ts();
+ time_t last_day_ts = stc_monitor_get_last_day_ts();
+
+ memset(&stat, 0, sizeof(stc_rstn_cumulative_data_s));
+ stat.month_start_ts = rstn_data->month_start_ts;
+ stat.week_start_ts = last_week_ts;
+ stat.day_start_ts = last_day_ts;
+
+ memset(&rule, 0, sizeof(table_statistics_select_rule));
+ rule.from = rstn_data->month_start_ts;
+ time(¤t_time);
+ rule.to = current_time;
+ rule.iftype = rstn_data->iftype;
+ rule.granularity = GRANULARITY;
+
+ table_statistics_per_app(rstn_data->app_id, &rule, __statistics_info_cb, &stat);
+
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA] = info.data_counter;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] = info.warn_counter;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] = info.monthly_counter + stat.monthly_stat;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] = info.weekly_counter + stat.weekly_stat;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY] = info.daily_counter + stat.daily_stat;
+
+ if (STC_DEBUG_LOG)
+ STC_LOGD("Rstn counter data[%lld] warn[%lld] "
+ "monthly[%lld] weekly[%lld] daily[%lld]",
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA],
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN],
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY],
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY],
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY]);
+ }
+
+ for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++) {
+ if (rstn_data->limit[i] >= 0) {
+ effective_limit[i] = rstn_data->limit[i] - rstn_data->counter[i];
+
+ if (effective_limit[i] < 0)
+ rstn_data->limit_exceeded |= (1 << i);
+ }
+ }
+
+ STC_LOGD("Rstn_id[%llu] limit[%lld] datausage[%lld]",
+ rstn_data->restriction_id,
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA],
+ info.data_counter);
+
+ if (rstn_data->limit_exceeded != 0 &&
+ rstn_data->limit_exceeded != (1 << STC_RSTN_LIMIT_TYPE_DATA_WARN)) {
+ __rstn_add_ipt_rule(rstn_data->classid, NFACCT_BLOCK, rstn_data->iftype);
+ }
+
+ rstn_data->rstn_state = STC_RSTN_STATE_ACTIVATED;
+
+ if (STC_DEBUG_LOG) {
+ STC_LOGD("Restriction activated "
+ "[\033[1;36m%d\033[0;m:\033[1;35m%d\033[0;m]",
+ rstn_data->classid, rstn_data->restriction_id);
+ }
+ }
+ break;
+ case RST_EXCLUDE:
+ __rstn_add_ipt_rule(rstn_data->classid, NFACCT_ALLOW,
+ rstn_data->iftype);
+
+ rstn_data->rstn_state = STC_RSTN_STATE_ACTIVATED;
+ rstn_data->limit_exceeded = 0;
+ rstn_data->limit_notified = 0;
+
+ if (STC_DEBUG_LOG) {
+ STC_LOGD("Restriction activated "
+ "[\033[1;36m%d\033[0;m:\033[1;35m%d\033[0;m]",
+ rstn_data->classid, rstn_data->restriction_id);
+ }
+ break;
+ case RST_UNSET:
+ {
+ int i;
+
+ if (rstn_data->classid == STC_TETHERING_APP_CLASSID)
+ __rstn_del_ipt_rule(rstn_data->classid, NFACCT_BLOCK,
+ rstn_data->iftype);
+ else
+ __rstn_del_ipt_rule(rstn_data->classid, rstn_data->rstn_type,
+ rstn_data->iftype);
+
+ rstn_data->rstn_state = STC_RSTN_STATE_DEACTIVATED;
+ rstn_data->limit_exceeded = 0;
+ rstn_data->limit_notified = 0;
+
+ for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++)
+ if (rstn_data->limit[i] >= 0)
+ rstn_data->counter[i] = 0;
+
+ __rstn_set_noti_state(STC_RSTN_STATE_UNSET);
+
+ if (STC_DEBUG_LOG) {
+ STC_LOGD("Restriction deactivated "
+ "[\033[1;36m%d\033[0;m:\033[1;35m%d\033[0;m]",
+ rstn_data->classid, rstn_data->restriction_id);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void __rstn_add(gpointer data, gpointer user_data)
+{
+ stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
+
+ /* rstn rule is activated */
+ if (rstn_data->rstn_state == STC_RSTN_STATE_ACTIVATED) {
+ if (STC_DEBUG_LOG) {
+ STC_LOGD("Restriction already activated "
+ "[\033[1;36m%d\033[0;m:\033[1;35m%d\033[0;m]",
+ rstn_data->classid, rstn_data->restriction_id);
+ }
+ return;
+ }
+
+ if (rstn_data->rstn_type == STC_RSTN_TYPE_ACCEPT) {
+ __rstn_process(RST_EXCLUDE,
+ rstn_data->app_id, rstn_data, user_data);
+ __rstn_tethering_process(RST_EXCLUDE,
+ rstn_data->app_id, rstn_data, user_data);
+ } else {
+ __rstn_process(RST_SET,
+ rstn_data->app_id, rstn_data, user_data);
+ __rstn_tethering_process(RST_SET,
+ rstn_data->app_id, rstn_data, user_data);
+ }
+
+ if (STC_DEBUG_LOG) {
+ __print_rstn(rstn_data);
+ STC_LOGD("\033[1;32mRestriction added\033[0;m "
+ "[\033[1;36m%d\033[0;m:\033[1;35m%d\033[0;m]",
+ rstn_data->classid, rstn_data->restriction_id);
+ }
+}
+
+static void __rstn_add_by_connection(gpointer key,
+ gpointer value, gpointer data)
+{
+ stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
+
+ g_slist_foreach(rstn_value->rules, __rstn_add, data);
+}
+
+static void __rstn_remove(gpointer data, gpointer user_data)
+{
+ stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
+
+ if (rstn_data->rstn_state == STC_RSTN_STATE_DEACTIVATED) {
+ STC_LOGD("\033[1;31mRestriction already deactivated\033[0;m "
+ "[\033[1;36m%d\033[0;m:\033[1;35m%d\033[0;m]",
+ rstn_data->classid, rstn_data->restriction_id);
+ return;
+ }
+
+ __rstn_process(RST_UNSET,
+ rstn_data->app_id, rstn_data, user_data);
+ __rstn_tethering_process(RST_UNSET,
+ rstn_data->app_id, rstn_data, user_data);
+
+ if (STC_DEBUG_LOG) {
+ __print_rstn(rstn_data);
+ STC_LOGD("\033[1;31mRestriction removed\033[0;m "
+ "[\033[1;36m%d\033[0;m:\033[1;35m%d\033[0;m]",
+ rstn_data->classid, rstn_data->restriction_id);
+ }
+}
+
+static void __rstn_remove_by_connection(gpointer key,
+ gpointer value, gpointer data)
+{
+ stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
+
+ g_slist_foreach(rstn_value->rules, __rstn_remove, data);
+}
+
+static void __rstn_update_counter_data(gpointer data,
+ gpointer user_data)
+{
+ stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
+
+ table_counters_info info = {
+ .restriction_id = rstn_data->restriction_id,
+ .data_counter = rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA],
+ .warn_counter = rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN],
+ .monthly_counter = rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY],
+ .weekly_counter = rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY],
+ .daily_counter = rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY]
+ };
+
+ table_counters_update_counters(&info);
+}
+
+static void __rstn_update_counter_value(gpointer key,
+ gpointer value, gpointer data)
+{
+ stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
+
+ g_slist_foreach(rstn_value->rules, __rstn_update_counter_data, NULL);
+}
+
+static void __rstn_data_destroy(gpointer data)
+{
+ stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
+
+ FREE(rstn_data->app_id);
+ FREE(rstn_data->ifname);
+ FREE(rstn_data->subscriber_id);
+ FREE(rstn_data->mac);
+
+ FREE(rstn_data);
+}
+
+static gint __rstn_data_comp(gconstpointer a, gconstpointer b)
+{
+ stc_rstn_data_s *da = (stc_rstn_data_s *)a;
+ stc_rstn_data_s *db = (stc_rstn_data_s *)b;
+
+ if ((da->iftype == db->iftype) &&
+ (g_strcmp0(da->ifname, db->ifname) == 0) &&
+ (g_strcmp0(da->subscriber_id, db->subscriber_id) == 0) &&
+ (da->roaming == db->roaming))
+ return 0;
+
+ return -1;
+}
+
+static stc_error_e __rstn_data_remove(stc_rstn_data_s *data)
+{
+ stc_rstn_value_s *lookup_value;
+ GSList *lookup_list;
+ stc_rstn_data_s *lookup_data;
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+
+ if (!rstns)
+ return STC_ERROR_NO_DATA;
+
+ lookup_value = g_hash_table_lookup(rstns, GUINT_TO_POINTER(data->classid));
+ if (!lookup_value) {
+ if (STC_DEBUG_LOG)
+ STC_LOGE("Restriction not found [\033[1;36m%d\033[0;m]",
+ data->classid);
+ return STC_ERROR_NO_DATA;
+ }
+
+ lookup_list = g_slist_find_custom(lookup_value->rules,
+ data, __rstn_data_comp);
+ if (!lookup_list) {
+ if (STC_DEBUG_LOG)
+ STC_LOGE("Restriction not found [%d:%s:%s:%d]",
+ data->iftype, data->ifname,
+ data->subscriber_id, data->roaming);
+ return STC_ERROR_NO_DATA;
+ }
+
+ lookup_data = lookup_list->data;
+
+ /* remove counter also */
+ table_counters_delete(lookup_data->restriction_id);
+ __rstn_remove(lookup_data, NULL);
+
+ lookup_value->rules = g_slist_remove(lookup_value->rules,
+ lookup_data);
+ __rstn_data_destroy(lookup_data);
+
+ if (!lookup_value->rules)
+ g_hash_table_remove(rstns, GUINT_TO_POINTER(data->classid));
+
+ return STC_ERROR_NONE;
+}
+
+static stc_error_e __rstn_data_add(stc_rstn_data_s *data)
+{
+ int i;
+ stc_rstn_value_s *lookup_value;
+ stc_rstn_value_s *rstn_value;
+ stc_rstn_data_s *rstn_data;
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+
+ if (!rstns)
+ return STC_ERROR_NO_DATA;
+
+ rstn_data = MALLOC0(stc_rstn_data_s, 1);
+ if (!rstn_data) {
+ if (STC_DEBUG_LOG)
+ STC_LOGE("Rstn_data allocation failed");
+ return STC_ERROR_OUT_OF_MEMORY;
+ }
+
+ lookup_value = g_hash_table_lookup(rstns, GUINT_TO_POINTER(data->classid));
+ if (!lookup_value) {
+ rstn_value = MALLOC0(stc_rstn_value_s, 1);
+ if (!rstn_value) {
+ if (STC_DEBUG_LOG)
+ STC_LOGE("Rstn_value allocation failed");
+ FREE(rstn_data);
+ return STC_ERROR_OUT_OF_MEMORY;
+ }
+
+ g_hash_table_insert(rstns, GUINT_TO_POINTER(data->classid),
+ rstn_value);
+ } else {
+ rstn_value = lookup_value;
+ }
+
+ rstn_data->classid = data->classid;
+ rstn_data->app_id = g_strdup(data->app_id);
+ rstn_data->iftype = data->iftype;
+ rstn_data->ifname = g_strdup(data->ifname);
+ rstn_data->subscriber_id = g_strdup(data->subscriber_id);
+ rstn_data->roaming = data->roaming;
+ rstn_data->mac = g_strdup(data->mac);
+
+ rstn_data->restriction_id = data->restriction_id;
+ rstn_data->rstn_state = data->rstn_state;
+ rstn_data->rstn_type = data->rstn_type;
+
+ for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++) {
+ rstn_data->limit[i] = data->limit[i];
+ rstn_data->counter[i] = 0;
+ }
+
+ rstn_data->limit_exceeded = 0;
+ rstn_data->limit_notified = 0;
+ rstn_data->month_start_date = data->month_start_date;
+ rstn_data->month_start_ts = data->month_start_ts;
+
+ __rstn_data_remove(rstn_data);
+ rstn_value->rules = g_slist_append(rstn_value->rules, rstn_data);
+
+ __rstn_add(rstn_data, NULL);
+
+ return STC_ERROR_NONE;
+}
+
+static void __rstn_value_destroy(gpointer data)
+{
+ stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)data;
+
+ g_slist_free_full(rstn_value->rules, __rstn_data_destroy);
+
+ FREE(rstn_value);
+}
+
+static stc_cb_ret_e __rstn_insert_cb(const table_restrictions_info *info,
+ void *user_data)
+{
+ stc_cb_ret_e ret = STC_CONTINUE;
+ stc_rstn_data_s data;
+
+ memset(&data, 0, sizeof(stc_rstn_data_s));
+
+ if (info->app_id) {
+ data.classid = get_classid_by_app_id(info->app_id, TRUE);
+ data.app_id = info->app_id;
+ } else
+ data.classid = STC_UNKNOWN_CLASSID;
+
+ data.iftype = info->iftype;
+ data.ifname = info->ifname;
+ data.subscriber_id = info->subscriber_id;
+ data.roaming = info->roaming;
+
+ data.rstn_type = info->rstn_type;
+ data.rstn_state = STC_RSTN_STATE_UNKNOWN;
+ data.restriction_id = info->restriction_id;
+
+ data.limit[STC_RSTN_LIMIT_TYPE_DATA] = info->data_limit;
+ data.limit[STC_RSTN_LIMIT_TYPE_DATA_WARN] = info->data_warn_limit;
+ data.limit[STC_RSTN_LIMIT_TYPE_MONTHLY] = info->monthly_limit;
+ data.limit[STC_RSTN_LIMIT_TYPE_WEEKLY] = info->weekly_limit;
+ data.limit[STC_RSTN_LIMIT_TYPE_DAILY] = info->daily_limit;
+
+ if (__rstn_data_add(&data) != STC_ERROR_NONE)
+ ret = STC_CANCEL;
+
+ return ret;
+}
+
+static void __rstn_update_counter(classid_bytes_context_s *context,
+ uint32_t classid)
+{
+ stc_rstn_value_s *lookup;
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+
+ if (!rstns)
+ return;
+
+ lookup = g_hash_table_lookup(rstns, GUINT_TO_POINTER(classid));
+ if (lookup) {
+ context->counter->classid = classid;
+ g_slist_foreach(lookup->rules,
+ stc_monitor_rstn_update_counter,
+ context);
+ }
+}
+
+static void __rstn_action_when_limit_exceeded_tethering(stc_rstn_data_s *rstn_data,
+ 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;
+ __rstn_del_tether_rule(counter->classid, mac_str,
+ NFACCT_TETH_BLOCK, rstn_data->iftype);
+
+ __rstn_add_tether_rule(counter->classid, mac_str,
+ NFACCT_TETH_BLOCK, rstn_data->iftype);
+ counter->intend = NFACCT_TETH_COUNTER;
+
+ g_free(mac_str);
+}
+
+static void __reset_time_counter_foreach_rstn_data(gpointer data,
+ gpointer user_data)
+{
+ stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
+ reset_time_limits_context_s *context =
+ (reset_time_limits_context_s *)user_data;
+ int i;
+ time_t now_month_start_ts;
+
+ if (rstn_data->month_start_date == 0) {
+ table_counters_info info;
+ memset(&info, 0, sizeof(table_counters_info));
+ table_counters_get_timestamps(rstn_data->restriction_id, &info);
+
+ if (info.month_start_date == 0)
+ rstn_data->month_start_date = 1;
+ else
+ rstn_data->month_start_date = info.month_start_date;
+ rstn_data->month_start_ts = info.month_start_ts;
+ }
+
+ now_month_start_ts =
+ stc_time_get_month_start(context->now,
+ rstn_data->month_start_date);
+
+ if (rstn_data->month_start_ts != now_month_start_ts) {
+ rstn_data->month_start_ts = now_month_start_ts;
+ context->month_start_ts = now_month_start_ts;
+ context->is_updated |= (1 << STC_RSTN_LIMIT_TYPE_MONTHLY);
+ }
+
+ if (context->is_updated) {
+ table_counters_info info;
+ memset(&info, 0, sizeof(table_counters_info));
+
+ info.restriction_id = rstn_data->restriction_id;
+ info.month_start_date = rstn_data->month_start_date;
+ info.month_start_ts = rstn_data->month_start_ts;
+ info.week_start_ts = context->week_start_ts;
+ info.day_start_ts = context->day_start_ts;
+
+ table_counters_update_timestamps(&info);
+ }
+
+ for (i = STC_RSTN_LIMIT_TYPE_MONTHLY; i < STC_RSTN_LIMIT_TYPE_MAX; i++) {
+
+ if ((context->is_updated) & (1 << i)) {
+ /* reset limit */
+ rstn_data->counter[i] = 0;
+
+ if (rstn_data->limit_exceeded & (1 << i)) {
+ /* remove iptables rule */
+ char *default_ifname = stc_default_connection_get_ifname();
+ struct nfacct_rule counter;
+ stc_s *stc = stc_get_manager();
+ if (stc == NULL) {
+ STC_LOGE("Can't get stc data");
+ g_free(default_ifname);
+ goto try_next_callback;
+ }
+
+ if (!stc->carg) {
+ stc->carg = MALLOC0(counter_arg_s, 1);
+ if (stc->carg == NULL) {
+ g_free(default_ifname);
+ goto try_next_callback;
+ }
+
+ stc->carg->sock = stc_monitor_get_contr_sock();
+ }
+
+ memset(&counter, 0, sizeof(struct nfacct_rule));
+
+ counter.carg = stc->carg;
+ counter.classid = rstn_data->classid;
+ counter.intend = NFACCT_BLOCK;
+ counter.iftype = rstn_data->iftype;
+ g_strlcpy(counter.ifname, default_ifname,
+ MAX_IFACE_LENGTH);
+
+ g_free(default_ifname);
+
+ /* iptables rule */
+ stc_monitor_ipt_del_in(&counter);
+ stc_monitor_ipt_del_out(&counter);
+
+ /* ip6tables rule */
+ stc_monitor_ip6t_del_in(&counter);
+ stc_monitor_ip6t_del_out(&counter);
+
+ rstn_data->rstn_state = STC_RSTN_STATE_DEACTIVATED;
+ rstn_data->limit_exceeded &= ~(1 << i);
+ rstn_data->limit_notified &= ~(1 << i);
+ }
+ }
+ }
+
+try_next_callback:
+ return;
+}
+
+static void __reset_time_counter_foreach_rstn_value(gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value;
+ g_slist_foreach(rstn_value->rules,
+ __reset_time_counter_foreach_rstn_data, data);
+}
+
+void stc_monitor_rstn_reset_time_counters_if_required(void)
+{
+ reset_time_limits_context_s context;
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+ time_t last_week_ts = stc_monitor_get_last_week_ts();
+ time_t last_day_ts = stc_monitor_get_last_day_ts();
+
+ context.now = time(NULL);
+ context.week_start_ts = stc_time_get_week_start(context.now);
+ context.day_start_ts = stc_time_get_day_start(context.now);
+ context.is_updated = 0;
+
+ if (last_week_ts != context.week_start_ts) {
+ stc_monitor_set_last_week_ts(context.week_start_ts);
+ context.is_updated |= (1 << STC_RSTN_LIMIT_TYPE_WEEKLY);
+ }
+
+ if (last_day_ts != context.day_start_ts) {
+ stc_monitor_set_last_day_ts(context.day_start_ts);
+ context.is_updated |= (1 << STC_RSTN_LIMIT_TYPE_DAILY);
+ }
+
+ if (rstns) {
+ g_hash_table_foreach(rstns,
+ __reset_time_counter_foreach_rstn_value,
+ &context);
+
+ if (context.is_updated)
+ STC_LOGD("Counter reset completed month_start[%ld] "
+ "week_start[%ld] day_start[%ld]",
+ context.month_start_ts, last_week_ts, last_day_ts);
+ }
+}
+
+void stc_monitor_rstn_update_counter(gpointer data,
+ gpointer user_data)
+{
+ int i;
+ stc_rstn_data_s *rstn_data = (stc_rstn_data_s *)data;
+ classid_bytes_context_s *context = (classid_bytes_context_s *)user_data;
+ default_connection_s *default_connection = stc_get_default_connection();
+
+ if (rstn_data->iftype != context->counter->iftype)
+ return;
+
+ if (rstn_data->ifname != NULL &&
+ g_strcmp0(rstn_data->ifname, "") &&
+ g_strcmp0(rstn_data->ifname, context->counter->ifname) != 0)
+ return;
+
+ if (rstn_data->subscriber_id != NULL &&
+ g_strcmp0(rstn_data->subscriber_id, "") &&
+ g_strcmp0(rstn_data->subscriber_id, default_connection->subscriber_id) != 0)
+ return;
+
+ if (rstn_data->roaming != default_connection->roaming)
+ return;
+
+ if (rstn_data->limit_exceeded != 0) {
+ context->data_limit_exceeded = TRUE;
+ return;
+ }
+
+ switch (context->counter->iotype) {
+ case NFACCT_COUNTER_IN:
+ case NFACCT_COUNTER_OUT:
+ if ((rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DATA_WARN] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_MONTHLY] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_WEEKLY] >= 0) ||
+ (rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY] == 0 &&
+ rstn_data->limit[STC_RSTN_LIMIT_TYPE_DAILY] >= 0)) {
+ table_counters_info info;
+ memset(&info, 0, sizeof(table_counters_info));
+ table_counters_get(rstn_data->restriction_id, &info);
+
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA] = info.data_counter;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] = info.warn_counter;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] = info.monthly_counter;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] = info.weekly_counter;
+ rstn_data->counter[STC_RSTN_LIMIT_TYPE_DAILY] = info.daily_counter;
+ }
+
+ for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++) {
+ if (rstn_data->limit[i] >= 0 &&
+ !(rstn_data->limit_notified & (1 << i))) {
+ rstn_data->counter[i] += context->bytes;
+ if (rstn_data->limit[i] <= rstn_data->counter[i])
+ stc_monitor_rstn_action_when_limit_exceeded(i,
+ rstn_data,
+ context);
+ }
+ }
+
+ stc_monitor_set_rstns_updated(TRUE);
+ __print_rstn(rstn_data);
+ break;
+ default:
+ STC_LOGE("Unknown iotype");
+ }
+}
+
+void stc_monitor_rstn_update_iface_counter(classid_bytes_context_s *context)
+{
+ switch (context->counter->iftype) {
+ case STC_IFACE_DATACALL:
+ __rstn_update_counter(context, STC_TOTAL_DATACALL_CLASSID);
+ break;
+ case STC_IFACE_WIFI:
+ __rstn_update_counter(context, STC_TOTAL_WIFI_CLASSID);
+ __rstn_update_counter(context, STC_TETHERING_APP_CLASSID);
+ break;
+ case STC_IFACE_BLUETOOTH:
+ __rstn_update_counter(context, STC_TOTAL_BLUETOOTH_CLASSID);
+ __rstn_update_counter(context, STC_TETHERING_APP_CLASSID);
+ break;
+ case STC_IFACE_USB:
+ __rstn_update_counter(context, STC_TETHERING_APP_CLASSID);
+ break;
+ case STC_IFACE_P2P:
+ __rstn_update_counter(context, STC_TETHERING_APP_CLASSID);
+ break;
+ default:
+ break;
+ }
+}
+
+void stc_monitor_rstn_action_when_limit_exceeded(stc_rstn_limit_type_e limit_type,
+ stc_rstn_data_s *rstn_data,
+ classid_bytes_context_s *context)
+{
+ gboolean rv;
+ char iftype[MAX_INT_LENGTH] = { 0, };
+ char byte[MAX_INT_LENGTH] = { 0, };
+ const char *signal_name = NULL;
+ const char *net_popup_content = NULL;
+ const char *net_popup_type = NULL;
+ stc_s *stc = (stc_s *)stc_get_manager();
+
+ if (stc == NULL) {
+ STC_LOGE("Failed to get stc data");
+ return;
+ }
+
+ switch (limit_type) {
+ case STC_RSTN_LIMIT_TYPE_DATA_WARN:
+ {
+ signal_name = "WarnThresholdCrossed";
+ net_popup_content = "warn threshold crossed";
+ net_popup_type = "warning_noti";
+ }
+ break;
+ case STC_RSTN_LIMIT_TYPE_DATA:
+ case STC_RSTN_LIMIT_TYPE_MONTHLY:
+ case STC_RSTN_LIMIT_TYPE_WEEKLY:
+ case STC_RSTN_LIMIT_TYPE_DAILY:
+ {
+ signal_name = "RestrictionThresholdCrossed";
+ net_popup_content = "restriction threshold crossed";
+ net_popup_type = "restriction_noti";
+
+ /* 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) {
+
+ if (g_str_has_suffix(rstn_data->app_id, STC_TETHERING_APP_SUFFIX) &&
+ rstn_data->classid != STC_TETHERING_APP_CLASSID) {
+ __rstn_action_when_limit_exceeded_tethering(rstn_data,
+ context);
+ }
+
+ } else {
+ /* block immediately */
+ context->counter->intend = NFACCT_BLOCK;
+ stc_monitor_ipt_del_in(context->counter);
+ stc_monitor_ipt_del_out(context->counter);
+ stc_monitor_ipt_add_in(context->counter);
+ stc_monitor_ipt_add_out(context->counter);
+
+ stc_monitor_ip6t_del_in(context->counter);
+ stc_monitor_ip6t_del_out(context->counter);
+ stc_monitor_ip6t_add_in(context->counter);
+ stc_monitor_ip6t_add_out(context->counter);
+ context->counter->intend = NFACCT_COUNTER;
+ }
+
+ rstn_data->limit_exceeded |= (1 << limit_type);
+ __rstn_set_noti_state(STC_RSTN_STATE_SET);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (signal_name == NULL) {
+ STC_LOGE("Invalid parameter: limit_type");
+ return;
+ }
+
+ /* emit signal */
+ rv = stc_manager_dbus_emit_signal(stc->connection,
+ STC_DBUS_SERVICE_RESTRICTION_PATH,
+ STC_DBUS_INTERFACE_RESTRICTION,
+ signal_name,
+ g_variant_new("(si)",
+ rstn_data->app_id,
+ rstn_data->iftype));
+
+ if (rv == TRUE)
+ rstn_data->limit_notified |= (1 << limit_type);
+
+ snprintf(iftype, MAX_INT_LENGTH, "%d", rstn_data->iftype);
+ snprintf(byte, MAX_INT_LENGTH, "%lld", rstn_data->limit[limit_type]);
+ stc_plugin_appstatus_send_message(net_popup_content,
+ net_popup_type, rstn_data->app_id, iftype, byte);
+
+ if (STC_DEBUG_LOG)
+ STC_LOGD("Limit exceeded [\033[0;31m%s\033[0;m:%d]",
+ net_popup_content, limit_type);
+}
+
+gboolean stc_monitor_rstn_flush_contr_to_db(gpointer user_data)
+{
+ time_t current_time = 0;
+ stc_s *stc = stc_get_manager();
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+ gboolean rstns_updated = stc_monitor_get_rstns_updated();
+
+ if (stc && stc->carg)
+ current_time = stc->carg->last_run_time;
+
+ if (rstns_updated == FALSE)
+ return G_SOURCE_REMOVE;
+
+ stc_monitor_set_rstns_updated(FALSE);
+
+ if (rstns)
+ g_hash_table_foreach(rstns,
+ __rstn_update_counter_value,
+ ¤t_time);
+
+ STC_LOGI("Flushed rstns counters to database");
+ return G_SOURCE_REMOVE;
+}
+
+stc_error_e stc_monitor_rstn_add(const table_restrictions_info *info)
+{
+ stc_rstn_data_s data;
+
+ memset(&data, 0, sizeof(stc_rstn_data_s));
+
+ if (info->app_id) {
+ data.classid = get_classid_by_app_id(info->app_id, TRUE);
+ data.app_id = info->app_id;
+ } else
+ data.classid = STC_UNKNOWN_CLASSID;
+
+ if (data.classid == STC_BACKGROUND_APP_CLASSID) {
+ stc_monitor_set_background_state(TRUE);
+ __vconf_set_int(VCONFKEY_STC_BACKGROUND_STATE, TRUE);
+ }
+
+ data.iftype = info->iftype;
+ data.ifname = info->ifname;
+ data.subscriber_id = info->subscriber_id;
+ data.roaming = info->roaming;
+ data.mac = info->mac;
+
+ data.rstn_type = info->rstn_type;
+ data.rstn_state = STC_RSTN_STATE_UNKNOWN;
+ data.restriction_id = info->restriction_id;
+
+ data.limit[STC_RSTN_LIMIT_TYPE_DATA] = info->data_limit;
+ data.limit[STC_RSTN_LIMIT_TYPE_DATA_WARN] = info->data_warn_limit;
+ data.limit[STC_RSTN_LIMIT_TYPE_MONTHLY] = info->monthly_limit;
+ data.limit[STC_RSTN_LIMIT_TYPE_WEEKLY] = info->weekly_limit;
+ data.limit[STC_RSTN_LIMIT_TYPE_DAILY] = info->daily_limit;
+ data.month_start_date = info->month_start_date;
+ data.month_start_ts = stc_time_get_month_start(time(NULL),
+ info->month_start_date);
+
+ return __rstn_data_add(&data);
+}
+
+void stc_monitor_rstn_add_for_app(uint32_t classid)
+{
+ stc_rstn_value_s *lookup_value;
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+
+ if (!rstns)
+ return;
+
+ lookup_value = g_hash_table_lookup(rstns, GUINT_TO_POINTER(classid));
+ if (!lookup_value) {
+ if (STC_DEBUG_LOG)
+ STC_LOGD("Restriction not found [\033[1;36m%d\033[0;m]",
+ classid);
+ return;
+ }
+
+ g_slist_foreach(lookup_value->rules, __rstn_add, NULL);
+}
+
+void stc_monitor_rstn_add_by_connection(default_connection_s *conn)
+{
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+
+ if (!rstns)
+ return;
+
+ g_hash_table_foreach(rstns, __rstn_add_by_connection, conn);
+}
+
+stc_error_e stc_monitor_rstn_remove(const table_restrictions_info *info)
+{
+ stc_rstn_data_s data;
+
+ memset(&data, 0, sizeof(stc_rstn_data_s));
+
+ data.classid = get_classid_by_app_id(info->app_id, TRUE);
+ data.app_id = info->app_id;
+
+ data.iftype = info->iftype;
+ data.ifname = info->ifname;
+ data.subscriber_id = info->subscriber_id;
+ data.roaming = info->roaming;
+
+ if (g_strcmp0(info->app_id, STC_BACKGROUND_APP_ID) == 0) {
+ stc_monitor_set_background_state(FALSE);
+ __vconf_set_int(VCONFKEY_STC_BACKGROUND_STATE, FALSE);
+ }
+
+ return __rstn_data_remove(&data);
+}
+
+void stc_monitor_rstn_remove_for_app(uint32_t classid)
+{
+ stc_rstn_value_s *lookup_value;
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+
+ if (!rstns)
+ return;
+
+ lookup_value = g_hash_table_lookup(rstns, GUINT_TO_POINTER(classid));
+ if (!lookup_value) {
+ if (STC_DEBUG_LOG)
+ STC_LOGD("Restriction not found [\033[1;36m%d\033[0;m]",
+ classid);
+ return;
+ }
+
+ g_slist_foreach(lookup_value->rules, __rstn_remove, NULL);
+}
+
+void stc_monitor_rstn_remove_by_connection(default_connection_s *conn)
+{
+ GHashTable *rstns = stc_monitor_get_system_rstns();
+
+ if (!rstns)
+ return;
+
+ g_hash_table_foreach(rstns, __rstn_remove_by_connection, conn);
+}
+
+void stc_monitor_rstns_load(void)
+{
+ table_restrictions_foreach(__rstn_insert_cb, NULL);
+
+ /* __rstn_tree_printall(); */
+}
+
+GHashTable *stc_monitor_rstns_init(void)
+{
+ return g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, __rstn_value_destroy);
+}