4 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
22 * @desc Datausage module
26 #include "appid-helper.h"
29 #include "counter-process.h"
32 #include "datausage-restriction.h"
33 #include "generic-netlink.h"
34 #include "net-cls-cgroup.h"
35 #include "nl-helper.h"
37 #include "notification.h" /* for sending datausage dbus notification */
38 #include "daemon-options.h"
39 #include "datausage-common.h"
40 #include "datausage-quota.h"
41 #include "datausage-vconf-callbacks.h"
44 #include "module-data.h"
46 #include "nfacct-rule.h"
47 #include "protocol-info.h"
48 #include "resourced.h"
49 #include "restriction-handler.h"
54 #include <linux/rtnetlink.h>
56 #ifdef CONFIG_DATAUSAGE_NFACCT
59 struct make_rule_context {
60 struct counter_arg *carg;
61 struct nfacct_rule *counter;
66 resourced_iface_type iftype;
67 nfacct_rule_direction iotype;
68 char ifname[MAX_NAME_LENGTH];
72 NFACCT_STATE_ACTIVE, /* kernel counter is applied */
73 NFACCT_STATE_DEACTIVATED, /* kernel counter was removed, but this counter
74 is still active, and it will be required for network interface,
75 when it will be activated */
80 enum nfacct_state state;
83 static nfacct_rule_jump get_jump_by_intend(struct nfacct_rule *counter)
85 if (counter->intend == NFACCT_WARN)
86 return NFACCT_JUMP_ACCEPT;
87 else if (counter->intend == NFACCT_BLOCK)
88 return NFACCT_JUMP_REJECT;
90 return NFACCT_JUMP_UNKNOWN;
93 static resourced_ret_c add_iptables_in(struct nfacct_rule *counter)
95 return produce_net_rule(counter, 0, 0,
96 NFACCT_ACTION_INSERT, get_jump_by_intend(counter),
100 static resourced_ret_c add_iptables_out(struct nfacct_rule *counter)
102 return produce_net_rule(counter, 0, 0,
103 NFACCT_ACTION_INSERT, get_jump_by_intend(counter),
107 static resourced_ret_c del_iptables_in(struct nfacct_rule *counter)
109 return produce_net_rule(counter, 0, 0,
110 NFACCT_ACTION_DELETE, get_jump_by_intend(counter),
114 static resourced_ret_c del_iptables_out(struct nfacct_rule *counter)
116 return produce_net_rule(counter, 0, 0,
117 NFACCT_ACTION_DELETE, get_jump_by_intend(counter),
121 #endif /* CONFIG_DATAUSAGE_NFACCT */
123 static void resourced_roaming_cb_init(void)
125 regist_roaming_cb(get_roaming_restriction_cb());
128 static int app_launch_cb(void *data)
130 struct proc_status *p_data = (struct proc_status*)data;
132 ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
133 "Please provide valid argument!");
134 ret = join_net_cls(p_data->appid, p_data->pid);
135 if (ret != RESOURCED_ERROR_NONE)
136 _D("Failed to start network counting.");
140 #ifdef CONFIG_DATAUSAGE_NFACCT
142 static int remove_each_counter(
147 struct nfacct_rule *counter = (struct nfacct_rule *)data;
148 resourced_iface_type iftype = *(resourced_iface_type *)value;
149 struct nfacct_key nf_key;
151 if (iftype == RESOURCED_IFACE_UNKNOWN)
154 nf_key.classid = counter->classid;
155 nf_key.iotype = counter->iotype;
156 counter->iftype = nf_key.iftype = iftype;
158 generate_counter_name(counter);
159 counter->iptables_rule(counter);
161 /* remove from local tree */
164 gconstpointer t = g_tree_lookup(counter->carg->nf_cntrs, &nf_key);
166 _I("Element exists, remove it!");
168 _D("Element doesn't exist!");
172 g_tree_remove(counter->carg->nf_cntrs, &nf_key);
175 gconstpointer t = g_tree_lookup(counter->carg->nf_cntrs, &nf_key);
177 _E("Element wasn't removed!");
184 static void remove_nfacct_counters_for_all_iface(u_int32_t classid, struct counter_arg *carg)
186 struct nfacct_rule counter = {
188 .iotype = NFACCT_COUNTER_IN,
189 .iptables_rule = del_iptables_in,
191 /* .name until we don't have iftype,
192 * we couldn't get name */
195 /* TODO rework for_each_ifindex to avoid cast,
196 * right now cast is necessary due for_each_ifindex directy pass
197 * given function into g_tree_foreach */
198 /* remove for ingress counter */
199 for_each_ifindex((ifindex_iterator)remove_each_counter, NULL, &counter);
200 /* remove for engress counter */
201 counter.iotype = NFACCT_COUNTER_OUT;
202 counter.iptables_rule = del_iptables_out;
203 for_each_ifindex((ifindex_iterator)remove_each_counter, NULL, &counter);
206 struct match_nftree_context
212 static gboolean match_pid(gpointer key,
216 struct match_nftree_context *ctx = (struct match_nftree_context *)data;
217 struct nfacct_value *nf_value = (struct nfacct_value *)value;
218 struct nfacct_key *nf_key = (struct nfacct_key *)key;
219 if (nf_value->pid == ctx->pid) {
220 ctx->classid = nf_key->classid;
226 static u_int32_t get_classid_by_pid(struct counter_arg *carg, const pid_t pid)
228 struct match_nftree_context ctx = {
230 .classid = RESOURCED_UNKNOWN_CLASSID,
232 g_tree_foreach(carg->nf_cntrs, match_pid, &ctx);
236 static int app_terminate_cb(void *data)
238 struct proc_status *p_data = (struct proc_status*)data;
239 struct shared_modules_data *m_data;
240 struct counter_arg *carg;
242 ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
243 "Please provide valid argument!");
245 m_data = get_shared_modules_data();
246 ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL,
247 "Can't get module data!");
250 ret_value_msg_if(carg == NULL, RESOURCED_ERROR_FAIL,
251 "Cant' get counter arg!");
252 classid = get_classid_by_pid(carg, p_data->pid);
253 ret_value_msg_if(classid == RESOURCED_UNKNOWN_CLASSID,
254 RESOURCED_ERROR_FAIL, "No classid to terminate!");
256 remove_nfacct_counters_for_all_iface(classid, carg);
257 return RESOURCED_ERROR_NONE;
260 static gboolean populate_classid_tree(gpointer key,
264 GTree *classid_tree = (GTree *)data;
265 struct nfacct_key *nf_key = (struct nfacct_key *)key;
266 struct nfacct_value *nf_value = (struct nfacct_value *)value;
268 if (nf_value->state == NFACCT_STATE_ACTIVE)
269 g_tree_insert(classid_tree, (const gpointer)nf_key->classid, NULL);
273 static gboolean remove_each_counter_by_classid(gpointer key,
277 u_int32_t classid = (u_int32_t)key;
278 struct counter_arg *carg = (struct counter_arg *)data;
279 remove_nfacct_counters_for_all_iface(classid, carg);
283 static gint pointer_compare(gconstpointer a, gconstpointer b)
288 static int add_one_tizen_os_counter(
293 struct counter_arg *carg = (struct counter_arg *)data;
294 struct nfacct_rule counter = {.name = {0}, .ifname = {0}, 0};
295 resourced_iface_type iftype = *(resourced_iface_type *)value;
297 if (iftype <= RESOURCED_IFACE_UNKNOWN ||
298 iftype >= RESOURCED_IFACE_LAST_ELEM)
301 counter.iotype = NFACCT_COUNTER_IN;
302 counter.iftype = iftype;
304 generate_counter_name(&counter);
305 add_iptables_in(&counter);
306 counter.iotype = NFACCT_COUNTER_OUT;
307 generate_counter_name(&counter);
308 add_iptables_out(&counter);
312 static void add_tizen_os_counters(struct counter_arg *carg) {
314 for_each_ifindex((ifindex_iterator)add_one_tizen_os_counter, NULL, carg);
317 static void reload_all_nf_counters(struct counter_arg *carg)
319 add_tizen_os_counters(carg);
320 /* it can be done by following ways:
321 * 1. just by reading existing net_cls cgroups, looks not robust because
322 * in this case we are getting network interface type from runtime, and
323 * it could be changed since the resourced was stopped. And it doesn't
324 * reflect counter state
325 * 2. By reading from iptables rules. We don't have C code for retriving
326 * it from kernel unless to use iptables cmd output, but it's not
327 * robust and not performance effective
328 * 3. Just by obtaining nfacct counters. We could do it without command
329 * line tool. It reflects current counter state, but not,
333 nfacct_send_initiate(carg);
336 static void remove_whole_nf_counters(struct counter_arg *carg)
338 GTree *classid_tree = g_tree_new(pointer_compare);; /* tree instead of array for avoiding
339 duplication, manual sort and binary search in case of array */
340 ret_msg_if(carg == NULL,
341 "Cant' get counter arg!");
343 /* fill classid list, due we couldn't iterate on tree and
344 * remove elements from it */
345 g_tree_foreach(carg->nf_cntrs, populate_classid_tree, classid_tree);
346 g_tree_foreach(classid_tree, remove_each_counter_by_classid, carg);
348 g_tree_destroy(carg->nf_cntrs);
349 g_tree_destroy(classid_tree);
352 /* notification section */
354 * TODO use following constant from kernel header
355 * nfacct/include/linux/netfilter/nfnetlink.h
357 #ifndef NFNLGRP_ACCT_QUOTA
358 #define NFNLGRP_ACCT_QUOTA 8
361 #define SOL_NETLINK 270
364 static inline char *get_public_appid(const uint32_t classid)
368 /* following value for ALL is suitable for using in statistics
369 what's why it's not in get_app_id_by_classid */
370 if (classid == RESOURCED_ALL_APP_CLASSID)
371 return RESOURCED_ALL_APP;
373 appid = get_app_id_by_classid(classid, true);
374 return !appid ? UNKNOWN_APP : appid;
377 static void init_nfacct(u_int32_t classid, pid_t pid,
378 nfacct_rule_direction ctype, struct counter_arg *carg,
379 struct nfacct_rule *counter)
381 counter->iotype = ctype;
382 counter->classid = classid;
383 counter->carg = carg;
385 counter->intend = NFACCT_COUNTER;
387 if (ctype == NFACCT_COUNTER_IN)
388 counter->iptables_rule = add_iptables_in;
389 else if (ctype == NFACCT_COUNTER_OUT)
390 counter->iptables_rule = add_iptables_out;
393 static resourced_ret_c del_counter(struct nfacct_rule *counter)
395 return produce_net_rule(counter, 0, 0,
396 NFACCT_ACTION_DELETE, get_jump_by_intend(counter),
400 static int fill_restriction(struct rtattr *attr_list[__NFACCT_MAX],
403 struct counter_arg *carg = (struct counter_arg *)user_data;
404 struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
405 char *cnt_name = (char *)RTA_DATA(
406 attr_list[NFACCT_NAME]);
409 resourced_restriction_info rst_info = {0};
411 init_nfacct(0, 0, 0, carg, &counter);
412 strcpy(counter.name, cnt_name);
413 recreate_counter_by_name(cnt_name, &counter);
415 app_id = get_public_appid(counter.classid);
416 ret = get_restriction_info(app_id, counter.iftype, &rst_info);
417 ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
418 "Failed to get restriction info!");
420 if (counter.intend == NFACCT_BLOCK) {
421 if (counter.iotype == NFACCT_COUNTER_IN) {
422 struct nfacct_rule out_counter = counter;
424 /* remove old ones, which were with notification */
425 counter.iotype = NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT;
426 ret = del_counter(&counter);
427 ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
428 "Can't delete restriction%s", counter.name);
430 out_counter.iotype = NFACCT_COUNTER_OUT;
431 generate_counter_name(&out_counter);
432 ret = add_iptables_out(&out_counter);
433 /* TODO need to think how to release it and what about
434 * not yet fired rule */
435 ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
436 "Can't create auxilary counter %s", out_counter.name);
439 if (rst_info.quota_id != NONE_QUOTA_ID)
440 send_restriction_notification(app_id);
441 update_restriction_db(app_id, counter.iftype, 0, 0,
442 RESOURCED_RESTRICTION_ACTIVATED,
443 rst_info.quota_id, rst_info.roaming);
445 } else if (counter.intend == NFACCT_WARN) {
446 if (rst_info.quota_id != NONE_QUOTA_ID)
447 send_restriction_warn_notification(app_id);
448 /* remove both warnings */
449 counter.iotype = NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT;
450 ret = del_counter(&counter);
451 ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
452 "Can't delete warning %s", counter.name);
454 _E("Unkown restriction notification type");
459 static Eina_Bool noti_func_cb(void *user_data, Ecore_Fd_Handler *fd_handler)
461 struct counter_arg *carg = (struct counter_arg *)user_data;
463 struct netlink_serialization_params ser_param = {0};
464 netlink_serialization_command *netlink_command = NULL;
467 _D("nfacct notification");
468 ret = read_netlink(carg->noti_fd, &ans, sizeof(struct genl));
472 ser_param.carg = carg;
473 ser_param.ans = &ans;
474 ser_param.eval_attr = fill_restriction;
475 netlink_command = netlink_create_command(&ser_param);
477 if (!netlink_command)
480 netlink_command->deserialize_answer(&(netlink_command->params));
483 return ECORE_CALLBACK_RENEW;
486 static void init_notifier(struct counter_arg *carg)
489 int option = NFNLGRP_ACCT_QUOTA;
490 struct sockaddr_nl addr;
491 socklen_t addr_len = sizeof(struct sockaddr_nl);
493 carg->noti_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
494 ret_msg_if(carg->noti_fd < 0, "Can't create socket");
497 memset(&addr, 0, sizeof(struct sockaddr_nl));
498 addr.nl_family = AF_NETLINK;
502 ret = bind(carg->noti_fd, (struct sockaddr *) &addr, addr_len);
503 ret_msg_if(ret < 0, "Can't bind notification socket");
505 ret = getsockname(carg->noti_fd, (struct sockaddr *)&addr, &addr_len);
506 ret_msg_if(ret < 0, "Can't get sockname!");
508 ret_msg_if(addr_len != sizeof(struct sockaddr_nl) ||
509 addr.nl_family != AF_NETLINK,
510 "getsockname bad argumetn");
514 ret = setsockopt(carg->noti_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
515 &option, sizeof(int));
516 ret_msg_if(carg->noti_fd < 0, "Can't set sock opt");
518 /* register handler */
519 carg->noti_fd_handler = ecore_main_fd_handler_add(
520 carg->noti_fd, ECORE_FD_READ, noti_func_cb,
522 ret_msg_if(carg->noti_fd_handler == NULL,
523 "Failed to add noti callbacks\n");
526 static void fini_notifier(struct counter_arg *carg)
528 shutdown(carg->noti_fd, SHUT_RDWR);
529 ecore_main_fd_handler_del(carg->noti_fd_handler);
530 close(carg->noti_fd);
533 /* end notification section */
535 static int app_terminate_cb(void *data)
540 iface_callback *create_counter_callback(void)
545 #endif /* CONFIG_DATAUSAGE_NFACCT */
547 static int resourced_datausage_init(void *data)
549 struct modules_arg *marg = (struct modules_arg *)data;
550 struct shared_modules_data *m_data = get_shared_modules_data();
553 load_daemon_opts(marg->opts);
554 _D("Initialize network counter function\n");
555 ret_value_msg_if(marg == NULL, RESOURCED_ERROR_INVALID_PARAMETER,
556 "Invalid modules argument\n");
557 ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL,
558 "Invalid shared modules data\n");
559 /* register notifier cb */
560 register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, app_launch_cb);
561 register_notifier(RESOURCED_NOTIFIER_APP_RESUME, app_launch_cb);
562 register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, app_launch_cb);
563 register_notifier(RESOURCED_NOTIFIER_APP_TERMINATE, app_terminate_cb);
564 m_data->carg = init_counter_arg(marg->opts);
565 ret_code = resourced_iface_init();
566 ret_value_msg_if(ret_code < 0, ret_code, "resourced_iface_init failed");
567 resourced_roaming_cb_init();
568 ret_code = resourced_init_counter_func(m_data->carg);
569 ret_value_msg_if(ret_code < 0, ret_code, "Error init counter func\n");
570 resourced_add_vconf_datausage_cb(m_data->carg);
571 init_hw_net_protocol_type();
572 reactivate_restrictions();
574 #ifdef CONFIG_DATAUSAGE_NFACCT
575 reload_all_nf_counters(m_data->carg);
577 /* let's make a notification socket */
578 init_notifier(m_data->carg);
580 return RESOURCED_ERROR_NONE;
583 static int resourced_datausage_finalize(void *data)
585 struct shared_modules_data *m_data = get_shared_modules_data();
587 _D("Finalize network counter function\n");
588 resourced_remove_vconf_datausage_cb();
589 ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL,
590 "Invalid shared modules data\n");
592 #ifdef CONFIG_DATAUSAGE_NFACCT
593 remove_whole_nf_counters(m_data->carg);
594 fini_notifier(m_data->carg);
596 resourced_finalize_counter_func(m_data->carg);
597 finalize_carg(m_data->carg);
598 finalize_storage_stm();
599 finalize_hw_net_protocol_type();
600 unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, app_launch_cb);
601 unregister_notifier(RESOURCED_NOTIFIER_APP_RESUME, app_launch_cb);
602 unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, app_launch_cb);
603 unregister_notifier(RESOURCED_NOTIFIER_APP_TERMINATE, app_terminate_cb);
604 resourced_iface_finalize();
607 return RESOURCED_ERROR_NONE;
610 #ifdef CONFIG_DATAUSAGE_NFACCT
612 static int compare_nfcntr(gconstpointer a, gconstpointer b,
613 gpointer UNUSED user_data)
615 struct nfacct_key *key_a = (struct nfacct_key *)a;
616 struct nfacct_key *key_b = (struct nfacct_key *)b;
617 int ret = key_a->classid - key_b->classid;
621 ret = key_a->iftype - key_b->iftype;
624 ret = key_a->iotype - key_b->iotype;
627 return strcmp(key_a->ifname, key_b->ifname);
630 GTree *create_nfacct_tree(void)
632 return g_tree_new_full(compare_nfcntr, NULL, NULL, free);
635 static struct nfacct_value *lookup_counter(struct nfacct_rule *counter)
637 struct nfacct_key key = {
638 .classid = counter->classid,
639 .iftype = counter->iftype,
640 .iotype = counter->iotype
642 STRING_SAVE_COPY(key.ifname, counter->ifname);
644 return (struct nfacct_value *)g_tree_lookup(counter->carg->nf_cntrs,
648 /* Called only in case of successful kernle operation */
649 void keep_counter(struct nfacct_rule *counter)
651 struct nfacct_key *key = NULL;
652 struct nfacct_value *value = NULL;
654 key = (struct nfacct_key *)malloc(sizeof(
656 ret_msg_if(key == NULL,
657 "Can allocate memory for nfacct_key!");
659 value = (struct nfacct_value *)malloc(sizeof(
660 struct nfacct_value));
664 _D("Can allocate memory for nfacct_key!");
668 key->classid = counter->classid;
669 key->iftype = counter->iftype;
670 key->iotype = counter->iotype;
671 STRING_SAVE_COPY(key->ifname, counter->ifname);
673 value->pid = counter->pid;
674 value->state = NFACCT_STATE_ACTIVE;
676 g_tree_insert(counter->carg->nf_cntrs, key, value);
679 static int create_each_iptable_rule(gpointer key, gpointer value, void *data)
681 struct make_rule_context *ctx = (struct make_rule_context *)data;
683 resourced_iface_type iftype = *(resourced_iface_type *)value;
684 struct nfacct_value *counter = NULL;
686 if (iftype <= RESOURCED_IFACE_UNKNOWN ||
687 iftype >= RESOURCED_IFACE_LAST_ELEM) {
688 _D("Unsupported network interface type %d",
690 return RESOURCED_ERROR_NONE;
693 ctx->counter->iftype = iftype;
694 generate_counter_name(ctx->counter);
695 counter = lookup_counter(ctx->counter);
696 if (counter != NULL) {
697 _D("Counter already exists!");
698 return RESOURCED_ERROR_NONE;
700 ret = ctx->counter->iptables_rule(ctx->counter);
701 ret_value_msg_if(ret != RESOURCED_ERROR_NONE, RESOURCED_ERROR_FAIL,
702 "Can't add iptables ingress rule");
704 keep_counter(ctx->counter);
705 return RESOURCED_ERROR_NONE;
708 static void populate_incomplete_counter(void *data)
710 struct make_rule_context *ctx = (struct make_rule_context *)data;
711 struct nfacct_value *counter;
712 generate_counter_name(ctx->counter);
714 counter = lookup_counter(ctx->counter);
715 if (counter != NULL) {
716 _D("Counter already exists!");
719 keep_counter(ctx->counter);
722 static resourced_ret_c create_iptables_rule(const char *app_id, const pid_t pid)
724 struct shared_modules_data *m_data = get_shared_modules_data();
725 struct counter_arg *carg = m_data->carg;
726 struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
727 struct make_rule_context ctx;
728 uint32_t classid = get_classid_by_app_id(app_id, false);
731 ctx.counter = &counter;
732 init_nfacct(classid, pid, NFACCT_COUNTER_IN, carg, &counter);
734 for_each_ifindex((ifindex_iterator)create_each_iptable_rule,
735 populate_incomplete_counter, &ctx);
737 counter.iotype = NFACCT_COUNTER_OUT;
738 counter.iptables_rule = add_iptables_out;
739 for_each_ifindex((ifindex_iterator)create_each_iptable_rule,
740 populate_incomplete_counter, &ctx);
742 return RESOURCED_ERROR_NONE;
745 /* iface reset section */
746 struct iftype_context {
747 resourced_iface_type iftype;
748 struct counter_arg *carg;
751 static bool is_incomplete_counter(struct nfacct_key *nfacct_key, struct nfacct_value *nfacct_value)
753 return nfacct_key->iftype == RESOURCED_IFACE_UNKNOWN &&
754 nfacct_value->state == NFACCT_STATE_ACTIVE;
755 /* special incomplete status unnecessary */
758 static gboolean activate_each_counter_by_iftype(gpointer key,
762 struct nfacct_key *nfacct_key = (struct nfacct_key *)key;
763 struct nfacct_value *nfacct_value = (struct nfacct_value *)value;
764 struct iftype_context *ctx = (struct iftype_context *)data;
765 struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
766 struct nfacct_value *found_counter;
767 int ret = RESOURCED_ERROR_NONE;
769 /* ugly check, due in case of RMNET -> WLAN switch,
770 * WLAN activated before then RMNET is deactivated */
773 * skip activating in case of
774 * 1. new interface is the same as was before
775 * 2. and counter is still active and new interface is Wifi
776 * such problem was with WiFi only
777 * 3. and state is not deactivated, it's mean we wil skip in case of active
780 if (!(ctx->iftype != nfacct_key->iftype &&
781 nfacct_value->state == NFACCT_STATE_ACTIVE &&
782 ctx->iftype == RESOURCED_IFACE_WIFI) &&
783 nfacct_value->state != NFACCT_STATE_DEACTIVATED &&
784 !is_incomplete_counter(nfacct_key, nfacct_value))
785 /* it means ctx->iftype was activated, but we still have
786 * active counter for another interface, assume
787 * WLAN is preffered, so lets deactivate it */
788 return FALSE; /* continue iteration */
791 counter.classid = nfacct_key->classid;
792 counter.iotype = nfacct_key->iotype;
793 counter.iftype = ctx->iftype;
794 counter.carg = ctx->carg;
796 generate_counter_name(&counter);
798 found_counter = lookup_counter(&counter);
799 ret_value_msg_if(found_counter != NULL &&
800 found_counter->state == NFACCT_STATE_ACTIVE, FALSE,
801 "Counter already exists and active!");
803 if (counter.iotype == NFACCT_COUNTER_IN)
804 ret = add_iptables_in(&counter);
805 else if (counter.iotype == NFACCT_COUNTER_OUT)
806 ret = add_iptables_out(&counter);
808 _E("Unknown counter direction: %s", counter.name);
812 if (ret != RESOURCED_ERROR_NONE)
815 if (found_counter != NULL && found_counter->state ==
816 NFACCT_STATE_DEACTIVATED)
817 found_counter->state = NFACCT_STATE_ACTIVE;
819 keep_counter(&counter);
824 static void handle_on_iface_up(const int ifindex)
826 /* NEW IFACE LET's add COUNTER if it DOESN"T exists */
827 resourced_iface_type iftype;
828 struct shared_modules_data *m_data;
829 struct iftype_context ctx;
830 m_data = get_shared_modules_data();
831 ret_msg_if(m_data == NULL,
832 "Can't get module data!");
833 iftype = get_iftype(ifindex);
835 ret_msg_if(iftype == RESOURCED_IFACE_UNKNOWN,
836 "Can't get iftype for remove counter");
839 ctx.carg = m_data->carg;
840 g_tree_foreach(ctx.carg->nf_cntrs, activate_each_counter_by_iftype, &ctx);
841 add_tizen_os_counters(m_data->carg);
844 struct del_counter_context
846 struct nfacct_value *nfacct_value;
847 struct nfacct_key *nfacct_key;
848 struct counter_arg *carg;
851 static Eina_Bool del_counter_delayed(void *data)
854 struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
855 struct del_counter_context *del_ctx = (struct del_counter_context *)data;
856 struct nfacct_value *nfacct_value = del_ctx->nfacct_value;
857 struct nfacct_key *nfacct_key = del_ctx->nfacct_key;
859 counter.classid = nfacct_key->classid;
860 counter.iotype = nfacct_key->iotype;
861 counter.iftype = nfacct_key->iftype;
862 counter.carg = del_ctx->carg;
863 STRING_SAVE_COPY(counter.ifname, nfacct_key->ifname);
865 generate_counter_name(&counter);
867 ret = del_counter(&counter);
869 ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ECORE_CALLBACK_CANCEL,
870 "Can't delete counter %s",
873 nfacct_value->state = NFACCT_STATE_DEACTIVATED;
875 return ECORE_CALLBACK_CANCEL;
878 static gboolean deactivate_each_counter_by_iftype(gpointer key,
882 struct nfacct_key *nfacct_key = (struct nfacct_key *)key;
883 struct nfacct_value *nfacct_value = (struct nfacct_value *)value;
884 struct iftype_context *ctx = (struct iftype_context *)data;
885 struct del_counter_context *del_ctx = NULL;
887 /* deactivate counters only for ctx->iftype interface */
888 if (ctx->iftype != nfacct_key->iftype)
889 return FALSE; /* continue iteration */
891 del_ctx = (struct del_counter_context *)malloc(
892 sizeof(struct del_counter_context));
893 ret_value_msg_if(del_ctx == NULL, FALSE,
894 "Can't allocate del_counter_context");
895 del_ctx->nfacct_key = nfacct_key;
896 del_ctx->nfacct_value = nfacct_value;
897 del_ctx->carg = ctx->carg;
898 ecore_timer_add(0, del_counter_delayed, del_ctx);
903 static void handle_on_iface_down(const int ifindex)
905 /* iface is gone, lets remove counter */
906 resourced_iface_type iftype;
907 struct shared_modules_data *m_data;
908 struct iftype_context ctx;
909 m_data = get_shared_modules_data();
910 ret_msg_if(m_data == NULL,
911 "Can't get module data!");
912 iftype = get_iftype(ifindex);
914 ret_msg_if(iftype == RESOURCED_IFACE_UNKNOWN,
915 "Can't get iftype for remove counter");
918 ctx.carg = m_data->carg;
919 g_tree_foreach(ctx.carg->nf_cntrs, deactivate_each_counter_by_iftype, &ctx);
922 iface_callback *create_counter_callback(void)
924 iface_callback *ret_arg = (iface_callback *)
925 malloc(sizeof(iface_callback));
928 _E("Malloc of iface_callback failed\n");
931 ret_arg->handle_iface_up = handle_on_iface_up;
932 ret_arg->handle_iface_down = handle_on_iface_down;
937 /* end iface reset section */
939 #endif /*DATAUSAGE_TYPE*/
941 resourced_ret_c join_net_cls(const char *app_id, const pid_t pid)
944 char pkgname[MAX_PATH_LENGTH];
945 extract_pkgname(app_id, pkgname, sizeof(pkgname));
946 ret = make_net_cls_cgroup_with_pid(pid, pkgname);
947 ret_value_if(ret != RESOURCED_ERROR_NONE, ret);
948 ret = update_classids();
949 ret_value_if(ret != RESOURCED_ERROR_NONE, ret);
950 #ifdef CONFIG_DATAUSAGE_NFACCT
951 /* Create iptable rule */
952 ret = create_iptables_rule(app_id, pid);
953 ret_value_if(ret != RESOURCED_ERROR_NONE, ret);
954 #endif /* CONFIG_DATAUSAGE_NFACCT */
955 return RESOURCED_ERROR_NONE;
958 static const struct module_ops datausage_modules_ops = {
959 .priority = MODULE_PRIORITY_NORMAL,
961 .init = resourced_datausage_init,
962 .exit = resourced_datausage_finalize,
965 MODULE_REGISTER(&datausage_modules_ops)