08740df4b7158510d4f7aba0afdfbcbc209279bc
[platform/core/telephony/tel-plugin-indicator.git] / src / s_indi_main.c
1 /*
2  * tel-plugin-indicator
3  *
4  * Copyright (c) 2014 Samsung Electronics Co. Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23
24 #include <glib.h>
25 #include <gio/gio.h>
26
27 #include <dd-display.h>
28 #include <vconf.h>
29 #include <tcore.h>
30 #include <server.h>
31 #include <hal.h>
32 #include <plugin.h>
33 #include <storage.h>
34 #include <queue.h>
35 #include <co_ps.h>
36 #include <co_context.h>
37 #include <co_sim.h>
38 #include <co_network.h>
39 #include <co_call.h>
40 #include <at.h>
41
42 #include "s_indi_main.h"
43 #include "s_indi_util.h"
44 #include "s_indi_log.h"
45
46 #define S_INDI_UPDATE_INTERVAL          1
47 #define S_INDI_NO_RX_PKT_TIMEOUT        60
48 #define S_INDI_PROC_FILE                        "/proc/net/dev"
49
50 #define S_INDI_DB_STORAGE_NAME                          "database"
51 #define S_INDI_DB_STORAGE_PATH                          "/opt/dbspace/.dnet.db"
52 #define S_INDI_VCONF_STORAGE_NAME                       "vconf"
53
54 #define S_INDI_ALLOC_USER_DATA(data, plugin, cp) \
55         do { \
56                 data = s_indi_malloc0(sizeof(__s_indi_cb_user_data)); \
57                 data->indi_plugin = plugin; \
58                 data->cp_name = cp; \
59         } while (0)
60
61 #define S_INDI_FREE_USER_DATA(data) \
62         do { \
63                 s_indi_free(data->cp_name); \
64                 s_indi_free(data); \
65         } while (0)
66
67 typedef struct {
68         TcorePlugin *indi_plugin;
69         gchar *cp_name;
70 } __s_indi_cb_user_data;
71
72 typedef struct {
73         struct global_data msg_id;
74         gboolean b_pm_lock;
75
76         GHashTable *state_info; /* HashTable of s_indi_cp_state_info_type with key = cp_name */
77
78         GHashTable *vconf_info; /* Mapping of enum tcore_storage_key to cp_name */
79 } s_indi_private_info;
80
81 /***************** HOOKS *****************/
82 static enum tcore_hook_return s_indi_on_hook_modem_plugin_removed(Server *server, CoreObject *source,
83                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data);
84 static enum tcore_hook_return s_indi_on_hook_modem_plugin_added(Server *server, CoreObject *source,
85                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data);
86 static enum tcore_hook_return s_indi_on_hook_voice_call_status(Server *server, CoreObject *source,
87                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data);
88 static enum tcore_hook_return s_indi_on_hook_sim_init(Server *server, CoreObject *source,
89                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data);
90 static enum tcore_hook_return s_indi_on_hook_net_register(Server *server, CoreObject *source,
91                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data);
92 static enum tcore_hook_return s_indi_on_hook_ps_call_status(Server *server, CoreObject *source,
93                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data);
94 static enum tcore_hook_return s_indi_on_hook_modem_power(Server *server, CoreObject *source,
95                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data);
96
97 /***************** VCONF Callbacks *****************/
98 static void s_indi_storage_key_callback(enum tcore_storage_key key, void *value, void *user_data);
99
100 /***************** Utilities: GDestroyNotifications *****************/
101 static void __s_indi_state_info_value_destroy_notification(gpointer data);
102 static void __s_indi_dev_info_value_destroy_notification(gpointer data);
103
104 /***************** Utilities: Indicator Plugin *****************/
105 static inline s_indi_private_info *__s_indi_get_priv_info(TcorePlugin *plugin);
106 static gboolean __s_indi_start_updater(TcorePlugin *indi_plugin, gchar *cp_name);
107 static gboolean __s_indi_update_callback(__s_indi_cb_user_data *data);
108 static void __s_indi_set_dormancy_value(Server *server, s_indi_dormancy_info_type *dormancy_info, enum tcore_storage_key key_fd);
109 static void __s_indi_refresh_modems(TcorePlugin *indi_plugin);
110 static s_indi_cp_state_info_type *__s_indi_alloc_state_info(CoreObject *co_ps);
111 static s_indi_dev_state_info_type *__s_indi_alloc_device_state(CoreObject *ps_context, s_indi_cp_state_info_type *parent);
112 static CoreObject *__s_indi_fetch_ps_co(TcorePlugin *plugin);
113
114 static void __s_indi_add_modem_plugin(TcorePlugin *indi_plugin, TcorePlugin *modem_plugin);
115 static void __s_indi_remove_modem_plugin(TcorePlugin *indi_plugin, TcorePlugin *modem_plugin);
116 static void __s_indi_register_vconf_key(enum tcore_storage_key key, TcorePlugin *indi_plugin, const char *cp_name);
117 static void __s_indi_unregister_vconf_key(enum tcore_storage_key key, TcorePlugin *indi_plugin, const char *cp_name);
118 static void __s_indi_process_fast_dormancy(s_indi_cp_state_info_type *state_info, GVariant *value);
119 static gboolean __s_indi_cancel_pm_lock(gboolean b_pm_lock);
120 static gboolean __s_indi_handle_voice_call_status(Server *server, CoreObject *source,
121         enum tcore_notification_command command, const char *cp_name,
122         s_indi_cp_state_info_type *state_info);
123
124 static void __s_indi_deactivate_ps_context (gpointer key, gpointer value, gpointer user_data);
125 static gboolean __s_indi_check_fast_dormancy(TcorePlugin *indi_plugin, CoreObject *co_ps, s_indi_dormancy_info_type *dormancy_info, gboolean b_pm_lock);
126
127 void __s_indi_process_fast_dormancy(s_indi_cp_state_info_type *state_info, GVariant *value)
128 {
129         gboolean fd_set = FALSE;
130         int on_timeout = S_INDI_ZERO;
131         int off_timeout = S_INDI_ZERO;
132
133         if (!g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
134                 err("wrong variant data type");
135                 return;
136         }
137
138         state_info->dormant_info.b_vconf_checker = TRUE;
139
140         fd_set = g_variant_get_int32(value);
141         dbg("fast dormancy set (%s)", fd_set ? "TRUE" : "FALSE");
142
143         if (fd_set) {
144                 on_timeout = S_INDI_FIVE;
145                 off_timeout = S_INDI_FIVE;
146         } else {
147                 on_timeout = S_INDI_MINUS_ONE;
148                 off_timeout = S_INDI_MINUS_ONE;
149         }
150         state_info->dormant_info.lcd_on_timeout = on_timeout;
151         state_info->dormant_info.lcd_off_timeout = off_timeout;
152         state_info->dormant_info.is_dormant_set = fd_set;
153 }
154
155 void __s_indi_register_vconf_key(enum tcore_storage_key key, TcorePlugin *indi_plugin, const char *cp_name)
156 {
157         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
158         Storage *strg_vconf = tcore_server_find_storage(tcore_plugin_ref_server(indi_plugin), S_INDI_VCONF_STORAGE_NAME);
159         s_indi_assert(NULL != strg_vconf);
160
161         /** NULL cp_name: subscription independent vconf key */
162         if (tcore_storage_set_key_callback(strg_vconf, key, s_indi_storage_key_callback, indi_plugin)
163                         && (NULL != cp_name))
164                 g_hash_table_insert(priv_info->vconf_info, GUINT_TO_POINTER(key), s_indi_strdup(cp_name));
165 }
166
167 void __s_indi_unregister_vconf_key(enum tcore_storage_key key, TcorePlugin *indi_plugin, const char *cp_name)
168 {
169         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
170         Storage *strg_vconf = tcore_server_find_storage(tcore_plugin_ref_server(indi_plugin), S_INDI_VCONF_STORAGE_NAME);
171         s_indi_assert(NULL != strg_vconf);
172
173         /** NULL cp_name: subscription independent vconf key */
174         if (tcore_storage_remove_key_callback(strg_vconf, key, s_indi_storage_key_callback)
175                 && (NULL != cp_name))
176                 g_hash_table_remove(priv_info->vconf_info, GUINT_TO_POINTER(key));
177 }
178
179 void __s_indi_add_modem_plugin(TcorePlugin *indi_plugin, TcorePlugin *modem_plugin)
180 {
181         gchar *cp_name = NULL;
182         enum tcore_storage_key vconf_key;
183         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
184
185         /** @todo: It may be possible to use cp_name without duping as well */
186         cp_name = s_indi_strdup(tcore_server_get_cp_name_by_plugin(modem_plugin));
187         s_indi_assert(NULL != cp_name);
188         s_indi_log_ex(cp_name, "Added");
189
190         /** @todo: Check if key-value replacement is the intended behavior */
191         g_hash_table_insert(priv_info->state_info, cp_name, __s_indi_alloc_state_info(__s_indi_fetch_ps_co(modem_plugin)));
192
193         if (s_indi_str_has_suffix(cp_name, "0")) {
194                 vconf_key = STORAGE_KEY_TESTMODE_FAST_DORMANCY;
195         } else if (s_indi_str_has_suffix(cp_name, "1")) {
196                 vconf_key = STORAGE_KEY_TESTMODE_FAST_DORMANCY2;
197         } else {
198                 s_indi_assert_not_reached();
199         }
200
201         __s_indi_register_vconf_key(vconf_key, indi_plugin, cp_name);
202 }
203
204 void __s_indi_remove_modem_plugin(TcorePlugin *indi_plugin, TcorePlugin *modem_plugin)
205 {
206         const char *cp_name = NULL;
207         enum tcore_storage_key vconf_key;
208         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
209
210         cp_name = tcore_server_get_cp_name_by_plugin(modem_plugin);
211         s_indi_assert(NULL != cp_name);
212         s_indi_assert(NULL != priv_info->state_info);
213
214         if (g_hash_table_remove(priv_info->state_info, cp_name))
215                 s_indi_log_ex(cp_name, "Removed");
216
217         if (s_indi_str_has_suffix(cp_name, "0")) {
218                 vconf_key = STORAGE_KEY_TESTMODE_FAST_DORMANCY;
219         } else if (s_indi_str_has_suffix(cp_name, "1")) {
220                 vconf_key = STORAGE_KEY_TESTMODE_FAST_DORMANCY2;
221         } else {
222                 s_indi_assert_not_reached();
223         }
224
225         __s_indi_unregister_vconf_key(vconf_key, indi_plugin, cp_name);
226 }
227
228 CoreObject *__s_indi_fetch_ps_co(TcorePlugin *plugin)
229 {
230         CoreObject *co_ps = NULL;
231         GSList *co_list = tcore_plugin_get_core_objects_bytype(plugin, CORE_OBJECT_TYPE_PS);
232         s_indi_assert(co_list != NULL);
233         s_indi_assert(g_slist_length(co_list) == S_INDI_ONE);
234
235         co_ps = g_slist_nth_data(co_list, S_INDI_ZERO);
236         s_indi_assert(co_ps != NULL);
237         g_slist_free(co_list);
238
239         return co_ps;
240 }
241
242 s_indi_cp_state_info_type *__s_indi_alloc_state_info(CoreObject *co_ps)
243 {
244         s_indi_cp_state_info_type *state_info = s_indi_malloc0(sizeof(s_indi_cp_state_info_type));
245         state_info->co_ps = co_ps;
246         state_info->ps_state = S_INDI_CELLULAR_UNKNOWN;
247         state_info->cp_trans_state = S_INDI_TRANSFER_UNKNOWN;
248         state_info->dormant_info.lcd_state = S_INDI_LCD_UNKNOWN;
249         state_info->dormant_info.lcd_on_timeout = S_INDI_MINUS_ONE;
250         state_info->dormant_info.lcd_off_timeout = S_INDI_MINUS_ONE;
251         state_info->rx_total = S_INDI_ZERO;
252         state_info->tx_total = S_INDI_ZERO;
253         state_info->dormant_info.parent = state_info;
254
255         /* tcore_context_get_ipv4_devname uses glib allocator so key should be freed using g_free() */
256         state_info->device_info = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, __s_indi_dev_info_value_destroy_notification);
257         return state_info;
258 }
259
260 s_indi_dev_state_info_type *__s_indi_alloc_device_state(CoreObject *ps_context, s_indi_cp_state_info_type *parent)
261 {
262         s_indi_dev_state_info_type *dev_state = s_indi_malloc0(sizeof(s_indi_dev_state_info_type));
263         dev_state->ps_context = ps_context;
264         dev_state->parent = parent;
265         return dev_state;
266 }
267
268 s_indi_private_info *__s_indi_get_priv_info(TcorePlugin *plugin)
269 {
270         s_indi_private_info *priv_info = tcore_plugin_ref_user_data(plugin);
271         s_indi_assert(NULL != priv_info);
272         return priv_info;
273 }
274
275 gboolean __s_indi_start_updater(TcorePlugin *indi_plugin, gchar *cp_name)
276 {
277         __s_indi_cb_user_data *cb_data = NULL;
278         s_indi_cp_state_info_type *state_info = NULL;
279         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
280
281         if ((state_info = g_hash_table_lookup(priv_info->state_info, cp_name)) == NULL) {
282                 warn("CP [%s] Not Present", cp_name);
283                 s_indi_free(cp_name);
284                 return FALSE;
285         }
286
287         if (state_info->src != NULL) {
288                 dbg("Another one is in progress");
289                 s_indi_free(cp_name);
290                 return FALSE;
291         }
292
293         S_INDI_ALLOC_USER_DATA(cb_data, indi_plugin, cp_name);
294
295         dbg("indicator is starting");
296         state_info->src = g_timeout_source_new_seconds(S_INDI_UPDATE_INTERVAL);
297         g_source_set_callback(state_info->src, (GSourceFunc)__s_indi_update_callback, cb_data, NULL);
298         g_source_set_priority(state_info->src, G_PRIORITY_HIGH);
299         g_source_attach(state_info->src, NULL);
300         g_source_unref(state_info->src);
301         return TRUE;
302 }
303
304 gboolean __s_indi_cancel_pm_lock(gboolean b_pm_lock)
305 {
306         /* Cancel power lock */
307         if (b_pm_lock) {
308                 int rv = S_INDI_ZERO;
309                 rv = display_unlock_state(LCD_OFF, PM_RESET_TIMER);
310                 dbg("display_unlock_state: rv(%d)", rv);
311         }
312
313         return FALSE;
314 }
315
316 gboolean __s_indi_update_callback(__s_indi_cb_user_data *data)
317 {
318 #define INDICATOR_BUFF_SIZE 4096
319         gchar buff[INDICATOR_BUFF_SIZE];
320         s_indi_cp_state_info_type *state_info = NULL;
321         s_indi_dev_state_info_type *dev_state = NULL;
322         TcorePlugin *indi_plugin = data->indi_plugin;
323         const char *cp_name = data->cp_name;
324         unsigned int modem_id;
325         FILE *pf = NULL;
326         gchar *rv = NULL;
327         unsigned long long rx_curr_total = S_INDI_ZERO, tx_curr_total = S_INDI_ZERO, rx_prev_total = S_INDI_ZERO, tx_prev_total = S_INDI_ZERO;
328         unsigned long rx_changes_total = S_INDI_ZERO, tx_changes_total = S_INDI_ZERO;
329         s_indi_transfer_state cp_state = S_INDI_TRANSFER_NORMAL; /* Assume no activity */
330         enum tcore_storage_key key_last_rcv, key_last_snt, key_total_rcv, key_total_snt, key_service_state;
331         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
332         Storage *strg_vconf = NULL;
333
334         /* VCONF Mapper */
335         if (s_indi_str_has_suffix(cp_name, "0")) {
336                 key_last_rcv = STORAGE_KEY_CELLULAR_PKT_LAST_RCV;
337                 key_last_snt = STORAGE_KEY_CELLULAR_PKT_LAST_SNT;
338                 key_total_rcv = STORAGE_KEY_CELLULAR_PKT_TOTAL_RCV;
339                 key_total_snt = STORAGE_KEY_CELLULAR_PKT_TOTAL_SNT;
340                 key_service_state = STORAGE_KEY_PACKET_SERVICE_STATE;
341                 modem_id = MODEM_ID_PRIMARY;
342         } else if (s_indi_str_has_suffix(cp_name, "1")) {
343                 key_last_rcv = STORAGE_KEY_CELLULAR_PKT_LAST_RCV2;
344                 key_last_snt = STORAGE_KEY_CELLULAR_PKT_LAST_SNT2;
345                 key_total_rcv = STORAGE_KEY_CELLULAR_PKT_TOTAL_RCV2;
346                 key_total_snt = STORAGE_KEY_CELLULAR_PKT_TOTAL_SNT2;
347                 key_service_state = STORAGE_KEY_PACKET_SERVICE_STATE2;
348                 modem_id = MODEM_ID_SECONDARY;
349         } else {
350                 err("Unhandled CP Name %s", cp_name);
351                 s_indi_assert_not_reached();
352                 S_INDI_FREE_USER_DATA(data);
353                 return G_SOURCE_REMOVE;
354         }
355
356         /* Check CP Name presence */
357         if ((state_info = g_hash_table_lookup(priv_info->state_info, cp_name)) == NULL) {
358                 warn("%s CP is not present", cp_name);
359                 goto EXIT;
360         }
361
362         /* Check dev_state presence */
363         if (g_hash_table_size(state_info->device_info) == S_INDI_ZERO) {
364                 msg("Nothing to update, aborting timer");
365                 goto EXIT;
366         }
367
368         /** @todo: Check if needs to be read atomically */
369         pf = fopen(S_INDI_PROC_FILE, "r");
370         if (pf == NULL) {
371                 err("indicator fail to open file(%s), errno(%d)", S_INDI_PROC_FILE, errno);
372                 goto EXIT;
373         }
374
375         /* Skip first line */
376         rv = fgets(buff, sizeof(buff), pf);
377         if (!rv) {
378                 err("fail to read file or reach EOF, plz check %s", S_INDI_PROC_FILE);
379                 goto EXIT;
380         }
381
382         /* Skip second line */
383         rv = fgets(buff, sizeof(buff), pf);
384         if (!rv) {
385                 err("fail to read file or reach EOF, plz check %s", S_INDI_PROC_FILE);
386                 goto EXIT;
387         }
388
389         /* Update all devices of state_info */
390         while (fgets(buff, sizeof(buff), pf)) {
391                 gchar *ifname = buff, *entry = NULL;
392
393                 /* Skip whitespaces */
394                 while (*ifname == ' ')
395                         ifname++;
396
397                 /* Terminate to read ifname */
398                 entry = strrchr(ifname, ':');
399                 *entry++ = '\0';
400
401                 /* Read device_info */
402                 /* Takes care of the fix: Fix the PLM p131003-03182. Sha-ID: 65544f0be8e60ae3f964921755a1e83fa8e71441*/
403                 if ((dev_state = g_hash_table_lookup(state_info->device_info, ifname)) != NULL) {
404                         gint result = S_INDI_ZERO;
405                         unsigned long rx_pkt = S_INDI_ZERO, tx_pkt = S_INDI_ZERO;
406                         /************************************************************************
407                         Sample Input of S_INDI_PROC_FILE
408                         ************************************************************************
409                         Inter-|   Receive                                                |  Transmit
410                          face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
411                             lo: 114955545   88409    0    0    0     0          0         0 114955545   88409    0    0    0     0       0          0
412                           eth0: 2714004148 6475059    0    0    0     0          0         0 72595891 8726308    0    0    0     0       0          0
413                         ************************************************************************/
414                         s_indi_log_v("Reading stats of interface %s", ifname);
415                         result = sscanf(entry, "%lu %*s %*s %*s %*s %*s %*s %*s %lu %*s %*s %*s %*s %*s %*s %*s", &rx_pkt, &tx_pkt);
416                         if (result <= S_INDI_ZERO) {
417                                 err("stats fail to get proc field => %d", result);
418                                 goto EXIT; /** @todo: REMOVE or CONTINUE ? */
419                         }
420
421                         /* Save per device */
422                         dev_state->prev_rx = dev_state->curr_rx;
423                         dev_state->prev_tx = dev_state->curr_tx;
424                         dev_state->curr_rx = rx_pkt;
425                         dev_state->curr_tx = tx_pkt;
426
427                         /* Compute CP totals */
428                         rx_curr_total += rx_pkt;
429                         tx_curr_total += tx_pkt;
430                         rx_prev_total += dev_state->prev_rx;
431                         tx_prev_total += dev_state->prev_tx;
432                 }
433         }
434
435         rx_changes_total = rx_curr_total - rx_prev_total;
436         tx_changes_total = tx_curr_total - tx_prev_total;
437
438         if (rx_changes_total) {
439                 cp_state |= S_INDI_TRANSFER_RX;
440         }
441         if (tx_changes_total) {
442                 cp_state |= S_INDI_TRANSFER_TX;
443         }
444
445         /* todo: reduce the number of conditions */
446         if (cp_state == S_INDI_TRANSFER_TX) {
447                 state_info->no_rx_pckt++;
448         }
449         else if (cp_state == S_INDI_TRANSFER_NORMAL) {
450                 /* todo: why check against 5 */
451                 if (state_info->no_rx_pckt > 5) {
452                         state_info->no_rx_pckt++;
453                 }
454                 state_info->dormant_info.dormant_cnt++;
455         }else {
456                 state_info->dormant_info.dormant_cnt  = 0;
457                 state_info->dormant_info.is_dormant = FALSE;
458         }
459
460         if (cp_state) {
461                 s_indi_log_txrx(modem_id, "Transfer State:[%d] rx_cnt:[%d] RX: [%10lu] TX: [%10lu]", cp_state, state_info->no_rx_pckt, rx_changes_total, tx_changes_total);
462         }
463
464         if (state_info->dormant_info.lcd_state < S_INDI_LCD_OFF) {
465                 if (state_info->cp_trans_state != cp_state) { /* New Transfer State */
466                         strg_vconf = tcore_server_find_storage(tcore_plugin_ref_server(indi_plugin), S_INDI_VCONF_STORAGE_NAME);
467                         s_indi_assert(NULL != strg_vconf);
468
469                         state_info->cp_trans_state = cp_state;
470                         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, cp_state);
471                         if (cp_state != S_INDI_TRANSFER_NORMAL) { /* Data activity */
472                                 s_indi_log_txrx(modem_id, "pkt_state[%d] rx_changes [%lu] tx_changes [%lu]",
473                                         cp_state, rx_changes_total, tx_changes_total);
474                                 tcore_storage_set_int(strg_vconf, key_last_rcv, rx_curr_total/1000);
475                                 tcore_storage_set_int(strg_vconf, key_last_snt, tx_curr_total/1000);
476                         }
477                 }
478         }
479
480         if (state_info->no_rx_pckt >= S_INDI_NO_RX_PKT_TIMEOUT) {
481                 state_info->no_rx_pckt = S_INDI_ZERO;
482                 dbg("request to disconnect all ps context");
483                 g_hash_table_foreach(state_info->device_info, __s_indi_deactivate_ps_context, state_info->co_ps);
484         }
485
486         priv_info->b_pm_lock = __s_indi_check_fast_dormancy(indi_plugin, state_info->co_ps, &state_info->dormant_info, priv_info->b_pm_lock);
487         fclose(pf);
488         return G_SOURCE_CONTINUE; /* Revisit after S_INDI_UPDATE_INTERVAL */
489
490 EXIT:
491         dbg("indicator is stopped");
492         if (pf) fclose(pf);
493
494         strg_vconf = tcore_server_find_storage(tcore_plugin_ref_server(indi_plugin), S_INDI_VCONF_STORAGE_NAME);
495         s_indi_assert(NULL != strg_vconf);
496
497         /* Update PS Call and indicator states */
498         tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, S_INDI_TRANSFER_NORMAL);
499         tcore_storage_set_int(strg_vconf, key_service_state, S_INDI_CELLULAR_OFF);
500         dbg("PS Call status (%s) - [DISCONNECTED]", cp_name);
501
502         if (state_info) {
503                 state_info->src = NULL;
504                 state_info->cp_trans_state = S_INDI_TRANSFER_NORMAL;
505                 state_info->ps_state = S_INDI_CELLULAR_OFF;
506
507                 /* Update total VCONF before dying updator */
508                 tcore_storage_set_int(strg_vconf, key_total_rcv, tcore_storage_get_int(strg_vconf, key_total_rcv) + state_info->rx_total);
509                 tcore_storage_set_int(strg_vconf, key_total_snt, tcore_storage_get_int(strg_vconf, key_total_snt) + state_info->tx_total);
510
511                 /** @todo: VCONF needs upgrade to support llu */
512                 s_indi_log_txrx(modem_id, "RX-TOTAL[%d] TX-TOTAL[%d]",
513                         tcore_storage_get_int(strg_vconf, key_total_rcv), tcore_storage_get_int(strg_vconf, key_total_snt));
514                 state_info->rx_total = S_INDI_ZERO;
515                 state_info->tx_total = S_INDI_ZERO;
516         }
517
518         S_INDI_FREE_USER_DATA(data);
519         return G_SOURCE_REMOVE;
520 }
521
522 static void __s_indi_deactivate_ps_context (gpointer key, gpointer value, gpointer user_data)
523 {
524 #if 1
525         dbg("Temp Fix: stopping deactivation from indicator ");
526         key = key;
527         value = value;
528         user_data = user_data;
529 #else
530         gchar *ifname = key;
531         s_indi_dev_state_info_type *dev_state = value;
532
533         if(dev_state->ps_context && user_data){
534                 dbg("Deactivating PS context [%p] which is associated with interface %s", dev_state->ps_context, ifname);
535                 tcore_ps_deactivate_context(user_data, dev_state->ps_context, NULL);
536         }
537 #endif
538         return;
539 }
540
541 void __s_indi_state_info_value_destroy_notification(gpointer data)
542 {
543         s_indi_cp_state_info_type *state_info = data;
544         const char *cp_name = NULL;
545         Storage *strg_vconf = NULL;
546         enum tcore_storage_key key_total_rcv, key_total_snt;
547         s_indi_assert(NULL != state_info);
548         s_indi_assert(NULL != state_info->co_ps);
549
550         cp_name = tcore_server_get_cp_name_by_plugin(tcore_object_ref_plugin(state_info->co_ps));
551         s_indi_assert(NULL != cp_name);
552         dbg("CP Name: [%s]", cp_name);
553
554         /* VCONF Mapper */
555         if (s_indi_str_has_suffix(cp_name, "0")) {
556                 key_total_rcv = STORAGE_KEY_CELLULAR_PKT_TOTAL_RCV;
557                 key_total_snt = STORAGE_KEY_CELLULAR_PKT_TOTAL_SNT;
558         } else if (s_indi_str_has_suffix(cp_name, "1")) {
559                 key_total_rcv = STORAGE_KEY_CELLULAR_PKT_TOTAL_RCV2;
560                 key_total_snt = STORAGE_KEY_CELLULAR_PKT_TOTAL_SNT2;
561         } else {
562                 err("Unhandled CP Name %s", cp_name);
563                 s_indi_assert_not_reached();
564                 goto OUT;
565         }
566
567         /* Free device nodes */
568         g_hash_table_destroy(state_info->device_info);
569         strg_vconf = tcore_server_find_storage(tcore_plugin_ref_server(tcore_object_ref_plugin(state_info->co_ps)), S_INDI_VCONF_STORAGE_NAME);
570         s_indi_assert(NULL != strg_vconf);
571
572         /* Update VCONF before dying */
573         tcore_storage_set_int(strg_vconf, key_total_rcv, tcore_storage_get_int(strg_vconf, key_total_rcv) + state_info->rx_total);
574         tcore_storage_set_int(strg_vconf, key_total_snt, tcore_storage_get_int(strg_vconf, key_total_snt) + state_info->tx_total);
575         dbg("CP[%s] RX-TOTAL[%10llu] TX-TOTAL[%10llu]", cp_name,
576                         tcore_storage_get_int(strg_vconf, key_total_rcv), tcore_storage_get_int(strg_vconf, key_total_snt));
577
578 OUT:
579         s_indi_free(state_info->dormant_info.mccmnc);
580         s_indi_free(data);
581 }
582
583 void __s_indi_dev_info_value_destroy_notification(gpointer data)
584 {
585         s_indi_dev_state_info_type *dev_state = data;
586         s_indi_cp_state_info_type *state_info = NULL;
587         s_indi_assert(NULL != dev_state);
588         state_info = dev_state->parent;
589         s_indi_assert(NULL != state_info);
590
591         /* Update parent before dying */
592         state_info->rx_total += dev_state->curr_rx/1000;
593         state_info->tx_total += dev_state->curr_tx/1000;
594
595         s_indi_log_v("DYING after contributing [RX: %lu][TX: %lu] OUT OF [RX: %llu][TX: %llu]",
596                 dev_state->curr_rx/1000, dev_state->curr_tx/1000,
597                 state_info->rx_total, state_info->tx_total);
598
599         s_indi_free(data);
600 }
601
602 void __s_indi_refresh_modems(TcorePlugin *indi_plugin)
603 {
604         GSList *mp_list = tcore_server_get_modem_plugin_list(tcore_plugin_ref_server(indi_plugin));
605         s_indi_log_v("Processing %u present modems", g_slist_length(mp_list));
606
607         while (mp_list) {
608                 __s_indi_add_modem_plugin(indi_plugin, mp_list->data);
609                 mp_list = mp_list->next;
610         }
611
612         g_slist_free(mp_list);
613 }
614
615 void __s_indi_set_dormancy_value(Server *server, s_indi_dormancy_info_type *dormancy_info, enum tcore_storage_key key_fd)
616 {
617         if (dormancy_info->b_vconf_checker) {
618                 Storage *strg_vconf = tcore_server_find_storage(server, S_INDI_VCONF_STORAGE_NAME);
619                 gboolean b_fd_force = tcore_storage_get_bool(strg_vconf, key_fd);
620
621                 s_indi_assert(NULL != strg_vconf);
622
623                 if (b_fd_force) {
624                         dbg("forcely enable fast dormancy ");
625                         dormancy_info->lcd_on_timeout = S_INDI_FIVE;
626                         dormancy_info->lcd_off_timeout = S_INDI_FIVE;
627                 } else {
628                         dbg("forcely disable fast dormancy ");
629                         dormancy_info->lcd_on_timeout = S_INDI_MINUS_ONE;
630                         dormancy_info->lcd_off_timeout = S_INDI_MINUS_ONE;
631                 }
632         }
633
634         if (!dormancy_info->mccmnc) {
635                 dbg("mccmnc is null");
636                 return;
637         }
638
639         /** @todo: Make List of blocked mccmnc and use that */
640         /*
641           * Fast dormancy values are updated currently only for SKT and KT operators in DB.Revisit.
642           *
643           */
644         if ((g_strcmp0((const char *)dormancy_info->mccmnc, "00101") == S_INDI_ZERO)
645                         || (g_strcmp0((const char *)dormancy_info->mccmnc, "99999") == S_INDI_ZERO)) {
646                 dormancy_info->lcd_on_timeout = S_INDI_ZERO;
647                 dormancy_info->lcd_off_timeout = S_INDI_ZERO;
648                 dbg("FD does not work in testsim");
649         }
650         else {
651 #define szQUERY_SIZE 5000
652                 Storage *strg_db;
653                 void *db_handle;
654                 char szQuery[szQUERY_SIZE];
655                 GHashTableIter iter;
656                 gpointer key, value;
657                 GHashTable *in_param, *out_param;
658
659
660                 /* Initialize Storage */
661                 strg_db = tcore_server_find_storage(server, S_INDI_DB_STORAGE_NAME);
662                 db_handle = tcore_storage_create_handle(strg_db, S_INDI_DB_STORAGE_PATH);
663                 if (db_handle == NULL) {
664                         err("Failed to get Storage handle");
665                         return;
666                 }
667
668                 /* Initialize parameters */
669                 in_param = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
670                 g_hash_table_insert(in_param, "1", g_strdup(dormancy_info->mccmnc));
671
672                 out_param = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)g_hash_table_destroy);
673
674                 memset(szQuery, '\0', szQUERY_SIZE);
675                 strcpy(szQuery, "select");
676                 strcat(szQuery, " a.dormant_id, a.network_info_id, a.lcd_on_timeout, a.lcd_off_timeout"); //0,1,2,3
677                 strcat(szQuery, " from fast_dormancy a, network_info b");
678                 strcat(szQuery, " where b.mccmnc= ? and a.network_info_id = b.network_info_id ");
679
680                 tcore_storage_read_query_database(strg_db, db_handle, szQuery, in_param, out_param, 4);
681
682                 dbg("Get dormancy value");
683                 g_hash_table_iter_init(&iter, out_param);
684                 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
685                         GHashTableIter iter2;
686                         gpointer key2, value2;
687
688                         if (value) {
689                                 g_hash_table_iter_init(&iter2, (GHashTable *)value);
690                                 while (g_hash_table_iter_next(&iter2, &key2, &value2) == TRUE) {
691                                         if (g_str_equal(key2, "2") == TRUE) {
692                                                 dormancy_info->lcd_on_timeout = atoi((const char*)value2);
693                                                 dbg("lcd on timeout(%d)", dormancy_info->lcd_on_timeout);
694                                         }
695                                         else if (g_str_equal(key2, "3") == TRUE) {
696                                                 dormancy_info->lcd_off_timeout = atoi((const char*)value2);
697                                                 dbg("lcd off timeout(%d)", dormancy_info->lcd_off_timeout);
698                                         }
699                                 }
700                                 break;
701                         }
702                 }
703
704                 /* Free resources */
705                 g_hash_table_destroy(in_param);
706                 g_hash_table_destroy(out_param);
707
708                 if(dormancy_info->lcd_on_timeout > 0 || dormancy_info->lcd_off_timeout > 0) {
709                         dormancy_info->is_dormant_set = TRUE;
710                 }
711
712                 /* De-initialize Storage */
713                 tcore_storage_remove_handle(strg_db, db_handle);
714         }
715 }
716
717 static gboolean __s_indi_check_fast_dormancy(TcorePlugin *indi_plugin, CoreObject *co_ps, s_indi_dormancy_info_type *dormancy_info, gboolean b_pm_lock)
718 {
719         int rv =0;
720
721         S_INDI_NOT_USED(indi_plugin);
722         S_INDI_NOT_USED(co_ps);
723
724         if(!dormancy_info->is_dormant_set){
725                 dormancy_info->dormant_cnt = 0;
726                 dormancy_info->is_dormant = FALSE;
727
728                 //cancle pm lock
729                 b_pm_lock = __s_indi_cancel_pm_lock(b_pm_lock);
730                 return b_pm_lock;
731         }
732
733         if(dormancy_info->is_dormant){
734                 dormancy_info->dormant_cnt = 0;
735                 return b_pm_lock;
736         }
737
738         if(dormancy_info->lcd_state < 3 && dormancy_info->lcd_on_timeout > 0){ //on 1 && dim 2
739
740                 //satisfy with fd condition, set fd and cancle the pm lock
741                 if(dormancy_info->dormant_cnt >= dormancy_info->lcd_on_timeout){
742                         dbg("set lcd on fast dormancy");
743                         dormancy_info->dormant_cnt = 0;
744                         dormancy_info->is_dormant = TRUE;
745                 }
746
747         }
748         else if(dormancy_info->lcd_state < 3 && dormancy_info->lcd_on_timeout <= 0){
749                 dormancy_info->dormant_cnt = 0;
750         }
751         else if(dormancy_info->lcd_state == 3 && dormancy_info->lcd_off_timeout > 0){ //off 3
752
753                 //call the pm lock state if pkt exist and not dormant state
754                 if(dormancy_info->dormant_cnt < dormancy_info->lcd_off_timeout){
755                         b_pm_lock = __s_indi_cancel_pm_lock(b_pm_lock);
756                         return b_pm_lock;
757                 }
758                 else if(dormancy_info->dormant_cnt >= dormancy_info->lcd_off_timeout){
759                         dbg("set lcd off fast dormancy");
760                         dormancy_info->dormant_cnt = 0;
761                         dormancy_info->is_dormant = TRUE;
762                 }
763         }
764         else if(dormancy_info->lcd_state == 3 && dormancy_info->lcd_off_timeout <= 0){ //off 3
765                 dormancy_info->dormant_cnt = 0;
766         }
767
768         //pm unlock
769         if(b_pm_lock){
770                 rv = display_unlock_state(LCD_OFF, PM_RESET_TIMER);
771                 b_pm_lock = FALSE;
772                 dbg("display_unlock_state: rv(%d)", rv);
773         }
774
775         return b_pm_lock;
776 }
777
778 void s_indi_storage_key_callback(enum tcore_storage_key key, void *value, void *user_data)
779 {
780         s_indi_cp_state_info_type *state_info = NULL;
781         GVariant *tmp = value;
782         s_indi_private_info *priv_info = __s_indi_get_priv_info(user_data);
783
784         s_indi_assert(NULL != tmp);
785
786         switch (key) {
787                 case STORAGE_KEY_TESTMODE_FAST_DORMANCY: /* Fall Through */
788                 case STORAGE_KEY_TESTMODE_FAST_DORMANCY2:
789                 {
790                         const gchar *cp_name = NULL;
791                         if ((cp_name = g_hash_table_lookup(priv_info->vconf_info, GUINT_TO_POINTER(key))) != NULL)
792                                 if ((state_info = g_hash_table_lookup(priv_info->state_info, cp_name)) != NULL) {
793                                         s_indi_log_ex(cp_name, "Processing Fast Dormancy");
794
795                                         /*TODO: Currently testmodem fast dormancy is not enabled.so process fast dormancy will not happen */
796
797                                         __s_indi_process_fast_dormancy(state_info, tmp);
798                                 }
799                 } break;
800
801                 case STORAGE_KEY_PM_STATE:
802                 {
803                         GHashTableIter iter;
804                         gpointer key, value;
805                         gint pm_state = S_INDI_ZERO;
806
807                         if (!g_variant_is_of_type(tmp, G_VARIANT_TYPE_INT32)) {
808                                 err("Wrong variant data type");
809                                 return;
810                         }
811
812                         pm_state = g_variant_get_int32(tmp);
813
814                         dbg("PM state Value:[%d]", pm_state);
815
816                         g_hash_table_iter_init(&iter, priv_info->state_info);
817                         while (g_hash_table_iter_next (&iter, &key, &value)) {
818                                 state_info = value;
819                                 state_info->dormant_info.lcd_state = pm_state;
820                         }
821                 } break;
822
823                 default:
824                         s_indi_assert_not_reached();
825         }
826 }
827
828 enum tcore_hook_return s_indi_on_hook_modem_power(Server *server, CoreObject *source,
829                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data)
830 {
831         struct tnoti_modem_power *modem_power = data;
832         s_indi_assert(modem_power != NULL);
833
834         S_INDI_NOT_USED(server);
835         S_INDI_NOT_USED(command);
836         S_INDI_NOT_USED(data_len);
837
838         CORE_OBJECT_CHECK_RETURN(source, CORE_OBJECT_TYPE_MODEM, TCORE_HOOK_RETURN_CONTINUE);
839
840         if (modem_power->state == MODEM_STATE_ERROR) { /* CP reset */
841                 TcorePlugin *indi_plugin = user_data;
842                 const char *cp_name = NULL;
843                 s_indi_cp_state_info_type *state_info = NULL;
844                 s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
845
846                 cp_name = tcore_server_get_cp_name_by_plugin(tcore_object_ref_plugin(source));
847                 s_indi_assert(NULL != cp_name);
848                 s_indi_log_ex(cp_name, "MODEM_STATE_ERROR");
849
850                 if ((state_info = g_hash_table_lookup(priv_info->state_info, cp_name)) == NULL) {
851                         warn("BAILING OUT: [%s] not found", cp_name);
852                         return TCORE_HOOK_RETURN_CONTINUE;
853                 }
854
855                 /* Remove all device states since PS releasing all contexts */
856                 g_hash_table_remove_all(state_info->device_info);
857
858                 /* Free MCC/MNC. It will be received again */
859                 s_indi_free(state_info->dormant_info.mccmnc);
860                 state_info->dormant_info.mccmnc = NULL;
861
862                 /* Reset Dormant Information @todo: Why is this required? */
863                 state_info->dormant_info.lcd_on_timeout = S_INDI_ZERO;
864                 state_info->dormant_info.lcd_off_timeout = S_INDI_ZERO;
865                 priv_info->b_pm_lock = __s_indi_cancel_pm_lock(priv_info->b_pm_lock);
866         }
867
868         return TCORE_HOOK_RETURN_CONTINUE;
869 }
870
871 enum tcore_hook_return s_indi_on_hook_ps_call_status(Server *server, CoreObject *source,
872                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data)
873 {
874         struct tnoti_ps_call_status *cstatus = data;
875         TcorePlugin *indi_plugin = user_data;
876         const char *cp_name = NULL;
877         s_indi_cp_state_info_type *state_info = NULL;
878         GHashTableIter iter;
879         gpointer cp_name_key, cp_state = NULL;
880         unsigned char active_pdp_count = S_INDI_ZERO;
881         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
882
883         s_indi_assert(cstatus != NULL);
884
885         S_INDI_NOT_USED(command);
886         S_INDI_NOT_USED(data_len);
887
888         CORE_OBJECT_CHECK_RETURN(source, CORE_OBJECT_TYPE_PS, TCORE_HOOK_RETURN_CONTINUE);
889
890         cp_name = tcore_server_get_cp_name_by_plugin(tcore_object_ref_plugin(source));
891         s_indi_assert(NULL != cp_name);
892
893         s_indi_log_ex(cp_name, "cid(%d) state(%d) reason(%d)",
894                 cstatus->context_id, cstatus->state, cstatus->result);
895
896         if (cstatus->state == S_INDI_PS_CALL_OK)
897                 return TCORE_HOOK_RETURN_CONTINUE;
898
899         if ((state_info = g_hash_table_lookup(priv_info->state_info, cp_name)) == NULL) {
900                 warn("BAILING OUT: [%s] not found", cp_name);
901                 return TCORE_HOOK_RETURN_CONTINUE;
902         }
903
904         s_indi_assert(source == state_info->co_ps);
905
906         if (cstatus->state == S_INDI_PS_CALL_CONNECT) {
907                 GSList *l_context = NULL;
908                 CoreObject *co_context = NULL;
909                 gchar *dev_name = NULL;
910                 s_indi_dev_state_info_type *dev_state = NULL;
911                 enum tcore_storage_key key_service_state, key_fd;
912                 Storage *strg_vconf = NULL;
913                 int role = CONTEXT_ROLE_UNKNOWN;
914                 gboolean data_allowed = FALSE;
915                 gboolean roaming_allowed = FALSE;
916
917                 /* Fetch context with internet/tethering role */
918                 l_context = tcore_ps_ref_context_by_id(source, cstatus->context_id);
919                 while (l_context) {
920                         role = tcore_context_get_role(l_context->data);
921                         if (role == CONTEXT_ROLE_INTERNET || role == CONTEXT_ROLE_TETHERING || role == CONTEXT_ROLE_MMS) {
922                                 co_context = l_context->data;
923                                 break;
924                         }
925
926                         l_context = l_context->next;
927                 }
928
929                 if (!co_context) {
930                         err("INTERNET/TETHERING/MMS role not found");
931                         return TCORE_HOOK_RETURN_CONTINUE;
932                 }
933
934                 dev_name = tcore_context_get_ipv4_devname(co_context); /* glib allocator */
935                 s_indi_assert(NULL != dev_name);
936
937                 /* Check if dev_name already exists */
938                 if (g_hash_table_lookup(state_info->device_info, dev_name)) {
939                         dbg("default connection is already connected");
940                         g_free(dev_name);
941                         return TCORE_HOOK_RETURN_CONTINUE;
942                 }
943
944                 /* Update Cellular State */
945                 if (s_indi_str_has_suffix(cp_name, "0")) {
946                         key_service_state = STORAGE_KEY_PACKET_SERVICE_STATE;
947                         key_fd = STORAGE_KEY_TESTMODE_FAST_DORMANCY;
948                 } else if (s_indi_str_has_suffix(cp_name, "1")) {
949                         key_service_state = STORAGE_KEY_PACKET_SERVICE_STATE2;
950                         key_fd = STORAGE_KEY_TESTMODE_FAST_DORMANCY2;
951                 } else {
952                         err("Un-handled CP");
953                         g_free(dev_name);
954                         s_indi_assert_not_reached();
955                         return TCORE_HOOK_RETURN_CONTINUE;
956                 }
957
958                 /* Fresh */
959                 strg_vconf = tcore_server_find_storage(server, S_INDI_VCONF_STORAGE_NAME);
960                 s_indi_assert(NULL != strg_vconf);
961
962                 data_allowed = tcore_storage_get_bool(strg_vconf, STORAGE_KEY_3G_ENABLE);
963                 roaming_allowed = tcore_storage_get_bool(strg_vconf, STORAGE_KEY_SETAPPL_STATE_DATA_ROAMING_BOOL);
964
965                 if (!data_allowed)
966                         return TCORE_HOOK_RETURN_CONTINUE;
967                 else if (state_info->roaming_status && !roaming_allowed)
968                         return TCORE_HOOK_RETURN_CONTINUE;
969
970                 /* Set Cellular state connected */
971                 if (role == CONTEXT_ROLE_INTERNET || role == CONTEXT_ROLE_TETHERING) {
972                         state_info->ps_state = S_INDI_CELLULAR_CONNECTED;
973                         tcore_storage_set_int(strg_vconf, key_service_state, S_INDI_CELLULAR_CONNECTED);
974                 }else if(role == CONTEXT_ROLE_MMS){
975                         state_info->ps_state = S_INDI_CELLULAR_MMS_CONNECTED;
976                         tcore_storage_set_int(strg_vconf, key_service_state, S_INDI_CELLULAR_MMS_CONNECTED);
977                 }
978
979                 /* Initialize Packet indicator to Normal */
980                 tcore_storage_set_int(strg_vconf, STORAGE_KEY_PACKET_INDICATOR_STATE, S_INDI_TRANSFER_NORMAL);
981                 state_info->cp_trans_state = S_INDI_TRANSFER_NORMAL;
982
983                 s_indi_log_ex(cp_name, "PS Call status - [CONNECTED]");
984
985                 /* Create new dev state */
986                 dev_state = __s_indi_alloc_device_state(co_context, state_info);
987                 g_hash_table_insert(state_info->device_info, dev_name, dev_state);
988
989                 key_fd = key_fd;
990
991                 /* Read & Update dormancy values */
992                 __s_indi_set_dormancy_value(server, &state_info->dormant_info, key_fd);
993
994                 /* Start Updater */
995                 __s_indi_start_updater(indi_plugin, s_indi_strdup(cp_name));
996
997         }
998         else if (cstatus->state == S_INDI_PS_CALL_NO_CARRIER) {
999                 gchar *dev_name = NULL;
1000                 GSList *l_context = tcore_ps_ref_context_by_id(source, cstatus->context_id);
1001
1002                 /* Remove all related contexts */
1003                 while (l_context) {
1004                         dev_name = tcore_context_get_ipv4_devname(l_context->data);
1005                         if (dev_name != NULL) {
1006                                 g_hash_table_remove(state_info->device_info, dev_name);
1007                                 g_free(dev_name);
1008                         }
1009                         l_context = l_context->next;
1010                 }
1011
1012                 g_hash_table_iter_init(&iter, (GHashTable *)priv_info->state_info);
1013                 while (g_hash_table_iter_next(&iter, &cp_name_key, &cp_state) == TRUE) {
1014                         s_indi_log_ex(cp_name_key, "State: [0x%x]", cp_state);
1015                         if (g_hash_table_size(((s_indi_cp_state_info_type *)cp_state)->device_info) != S_INDI_ZERO) {
1016                                 active_pdp_count++;
1017                                 break;
1018                         }
1019                 }
1020
1021                 /* Cancel PM Lock if there doens't exist any active PDP connection */
1022                 if (active_pdp_count == S_INDI_ZERO) {
1023                         dbg("No Active PDP context. Resetting 'PM Lock' status");
1024                         priv_info->b_pm_lock = __s_indi_cancel_pm_lock(priv_info->b_pm_lock);
1025                 }
1026         }
1027
1028         return TCORE_HOOK_RETURN_CONTINUE;
1029 }
1030
1031 enum tcore_hook_return s_indi_on_hook_net_register(Server *server, CoreObject *source,
1032                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data)
1033 {
1034         TcorePlugin *indi_plugin = user_data;
1035         const char *cp_name = NULL;
1036         s_indi_cp_state_info_type *state_info = NULL;
1037         gboolean active = FALSE;
1038         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
1039         gboolean gsm_dtm_support = FALSE;
1040         struct tnoti_network_registration_status *regist_status = data;
1041         int roaming_status = S_INDI_ZERO;
1042
1043         S_INDI_NOT_USED(command);
1044         S_INDI_NOT_USED(data_len);
1045         CORE_OBJECT_CHECK_RETURN(source, CORE_OBJECT_TYPE_NETWORK, TCORE_HOOK_RETURN_CONTINUE);
1046
1047         cp_name = tcore_server_get_cp_name_by_plugin(tcore_object_ref_plugin(source));
1048         s_indi_assert(NULL != cp_name);
1049         s_indi_assert(NULL != regist_status);
1050
1051         if ((state_info = g_hash_table_lookup(priv_info->state_info, cp_name)) == NULL) {
1052                 warn("BAILING OUT: [%s] not found", cp_name);
1053                 return TCORE_HOOK_RETURN_CONTINUE;
1054         }
1055
1056         roaming_status = state_info->roaming_status = regist_status->roaming_status;
1057         gsm_dtm_support = tcore_network_get_gsm_dtm_support(source);
1058
1059         s_indi_log_ex(cp_name, "roam_status: [0x%x] dtm_support: [0x%x]",
1060                 roaming_status, gsm_dtm_support);
1061
1062         if (gsm_dtm_support)
1063                 return TCORE_HOOK_RETURN_CONTINUE;
1064
1065         active = (g_hash_table_size(state_info->device_info) >= S_INDI_ONE) ? TRUE : FALSE;
1066
1067         if (active) {
1068                 Storage *strg_vconf = NULL;
1069                 GSList *co_list = NULL;
1070                 CoreObject *co_call = NULL;
1071                 unsigned int total_call_cnt = S_INDI_ZERO;
1072                 enum telephony_network_service_type svc_type;
1073                 enum tcore_storage_key key_service_state;
1074                 gboolean roaming_allowed = FALSE;
1075
1076                 /* VCONF Mapper */
1077                 if (s_indi_str_has_suffix(cp_name, "0")) {
1078                         key_service_state = STORAGE_KEY_PACKET_SERVICE_STATE;
1079                 } else if (s_indi_str_has_suffix(cp_name, "1")) {
1080                         key_service_state = STORAGE_KEY_PACKET_SERVICE_STATE2;
1081                 } else {
1082                         err("Un-handled CP");
1083                         s_indi_assert_not_reached();
1084                         return TCORE_HOOK_RETURN_CONTINUE;
1085                 }
1086
1087                 strg_vconf = tcore_server_find_storage(server, S_INDI_VCONF_STORAGE_NAME);
1088                 roaming_allowed = tcore_storage_get_bool(strg_vconf, STORAGE_KEY_SETAPPL_STATE_DATA_ROAMING_BOOL);
1089
1090                 svc_type = regist_status->service_type;
1091                 s_indi_log_ex(cp_name, "srvc_type(%d), roaming_allowed(%d)",
1092                         svc_type, roaming_allowed);
1093
1094                 /**
1095                  * If Roaming is NOT allowed and indication provides Roaming
1096                  * status Available, there is a mismatch.
1097                  * Set Cellular state OFF.
1098                  */
1099                 if (state_info->ps_state != S_INDI_CELLULAR_OFF && !roaming_allowed && roaming_status) {
1100                         tcore_storage_set_int(strg_vconf, key_service_state, S_INDI_CELLULAR_OFF); /* Set Cellular State OFF */
1101
1102                         /*   Indicator need not know worry about roaming status. packet service plugin should take care of de-activating the contexts
1103                                 when roaming is enabled and network enters roaming. When all the contexts associated with that network is de-activated. Indicator
1104                                 plugin will automatically ps status for that CP to S_INDI_CELLULAR_OFF
1105                         */
1106                         state_info->ps_state = S_INDI_CELLULAR_OFF; /* Update cache */
1107
1108                         s_indi_log_ex(cp_name, "PS Call status - [DISCONNECTED]");
1109                         return TCORE_HOOK_RETURN_CONTINUE;
1110                 }
1111
1112                 if (svc_type < NETWORK_SERVICE_TYPE_2G || svc_type > NETWORK_SERVICE_TYPE_2_5G_EDGE)
1113                         return TCORE_HOOK_RETURN_CONTINUE;
1114
1115                 co_list = tcore_plugin_get_core_objects_bytype(tcore_object_ref_plugin(source), CORE_OBJECT_TYPE_CALL);
1116                 if (!co_list) {
1117                         err("[ error ] co_list : NULL");
1118                         return TCORE_HOOK_RETURN_CONTINUE;
1119                 }
1120                 s_indi_assert(g_slist_length(co_list) == S_INDI_ONE);
1121
1122                 co_call = (CoreObject *)co_list->data;
1123                 g_slist_free(co_list);
1124
1125                 total_call_cnt = tcore_call_object_total_length(co_call);
1126                 s_indi_log_ex(cp_name, "totall call cnt (%d)", total_call_cnt);
1127
1128                 if (total_call_cnt > S_INDI_ONE) {
1129                         s_indi_cellular_state pkg_state = S_INDI_CELLULAR_UNKNOWN;
1130                         pkg_state = tcore_storage_get_int(strg_vconf, key_service_state);
1131                         if (pkg_state != S_INDI_CELLULAR_OFF) {
1132                                 tcore_storage_set_int(strg_vconf, key_service_state, S_INDI_CELLULAR_OFF);
1133                                 state_info->ps_state = S_INDI_CELLULAR_OFF; /* Update cache */
1134                         }
1135                 }
1136         }
1137
1138         return TCORE_HOOK_RETURN_CONTINUE;
1139 }
1140
1141 enum tcore_hook_return s_indi_on_hook_sim_init(Server *server, CoreObject *source,
1142                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data)
1143 {
1144         struct tnoti_sim_status *sim_data = data;
1145         enum tcore_storage_key fd_key;
1146         s_indi_assert(NULL != sim_data);
1147
1148         S_INDI_NOT_USED(command);
1149         S_INDI_NOT_USED(data_len);
1150
1151         CORE_OBJECT_CHECK_RETURN(source, CORE_OBJECT_TYPE_SIM, TCORE_HOOK_RETURN_CONTINUE);
1152
1153         if (sim_data->sim_status == SIM_STATUS_INIT_COMPLETED) {
1154                 struct tel_sim_imsi *sim_imsi = NULL;
1155                 const char *cp_name = NULL;
1156                 s_indi_cp_state_info_type *state_info = NULL;
1157                 TcorePlugin *indi_plugin = user_data;
1158                 s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
1159
1160                 cp_name = tcore_server_get_cp_name_by_plugin(tcore_object_ref_plugin(source));
1161                 s_indi_assert(NULL != cp_name);
1162                 s_indi_log_ex(cp_name, "SIM_STATUS_INIT_COMPLETED");
1163
1164                 if ((state_info = g_hash_table_lookup(priv_info->state_info, cp_name)) == NULL) {
1165                         warn("BAILING OUT: [%s] not found", cp_name);
1166                         return TCORE_HOOK_RETURN_CONTINUE;
1167                 }
1168
1169                 sim_imsi = tcore_sim_get_imsi(source);
1170                 s_indi_assert(NULL != sim_imsi);
1171                 state_info->dormant_info.mccmnc = s_indi_strdup((gchar *)sim_imsi->plmn);
1172                 free(sim_imsi); /* libc allocator */
1173
1174                 /* Update Cellular State */
1175                 if (s_indi_str_has_suffix(cp_name, "0")) {
1176                         fd_key = STORAGE_KEY_TESTMODE_FAST_DORMANCY;
1177                 } else if (s_indi_str_has_suffix(cp_name, "1")) {
1178                         fd_key = STORAGE_KEY_TESTMODE_FAST_DORMANCY2;
1179                 } else {
1180                         err("Un-handled CP");
1181                         return TCORE_HOOK_RETURN_CONTINUE;
1182                 }
1183
1184                 /* Caching the lcdontimer and lcdofftimer dormant values for different network from db */
1185                 __s_indi_set_dormancy_value(server, &(state_info->dormant_info), fd_key);
1186         }
1187
1188         return TCORE_HOOK_RETURN_CONTINUE;
1189 }
1190
1191 gboolean __s_indi_handle_voice_call_status(Server *server, CoreObject *source,
1192         enum tcore_notification_command command, const char *cp_name,
1193         s_indi_cp_state_info_type *state_info)
1194 {
1195         CoreObject *co_network = NULL;
1196         enum tcore_storage_key vconf_key;
1197         Storage *strg_vconf;
1198         enum telephony_network_service_type svc_type;
1199         gboolean show_icon = TRUE;
1200
1201         if (g_hash_table_size(state_info->device_info) == S_INDI_ZERO) {
1202                 s_indi_log_ex(cp_name, "PS state is already OFF");
1203                 return TRUE;
1204         }
1205
1206         co_network = tcore_plugin_ref_core_object(tcore_object_ref_plugin(state_info->co_ps),
1207                                         CORE_OBJECT_TYPE_NETWORK);
1208
1209         if (co_network) {
1210                 gboolean gsm_dtm_support = FALSE;
1211                 gsm_dtm_support = tcore_network_get_gsm_dtm_support(co_network);
1212                 if (gsm_dtm_support) {
1213                         s_indi_log_ex(cp_name, "GSM DTM supported! UI need not be synchronized");
1214                         return TRUE;
1215                 }
1216         }
1217
1218         /* Mapping VCONF keys */
1219         if (s_indi_str_has_suffix(cp_name, "0")) {
1220                 vconf_key = STORAGE_KEY_PACKET_SERVICE_STATE;
1221         } else if (s_indi_str_has_suffix(cp_name, "1")) {
1222                 vconf_key = STORAGE_KEY_PACKET_SERVICE_STATE2;
1223         } else {
1224                 s_indi_assert_not_reached();
1225                 return TRUE;
1226         }
1227
1228         tcore_network_get_service_type(co_network, &svc_type);
1229
1230         switch (svc_type) {
1231                 case NETWORK_SERVICE_TYPE_2G:
1232                 case NETWORK_SERVICE_TYPE_2_5G:
1233                 case NETWORK_SERVICE_TYPE_2_5G_EDGE:
1234                         show_icon = FALSE;
1235                         break;
1236
1237                 case NETWORK_SERVICE_TYPE_3G:
1238                 case NETWORK_SERVICE_TYPE_HSDPA:
1239                         if (tcore_object_ref_plugin(co_network) != tcore_object_ref_plugin(source))
1240                                 show_icon = FALSE;
1241                         break;
1242
1243                 default:
1244                         break;
1245         }
1246
1247         s_indi_log_ex(cp_name, "RAT: [0x%x], ps_state: [0x%x], show_icon[%d]",
1248                 svc_type, state_info->ps_state, show_icon);
1249
1250         if (show_icon == TRUE) {
1251                 if (state_info->ps_state == S_INDI_CELLULAR_OFF) {
1252                         state_info->ps_state = S_INDI_CELLULAR_CONNECTED;
1253                         goto OUT;
1254                 }
1255                 return TRUE;
1256         }
1257
1258         switch(command) {
1259                 case TNOTI_CALL_STATUS_IDLE: {
1260                         int total_call_cnt = S_INDI_ZERO;
1261                         total_call_cnt = tcore_call_object_total_length(source);
1262                         if (total_call_cnt > S_INDI_ONE) {
1263                                 s_indi_log_ex(cp_name, "Call is still connected");
1264                                 return TRUE;
1265                         }
1266                         state_info->ps_state = S_INDI_CELLULAR_CONNECTED;
1267                 } break;
1268
1269                 case TNOTI_CALL_STATUS_DIALING:
1270                 case TNOTI_CALL_STATUS_INCOMING:
1271                 case TNOTI_CALL_STATUS_ACTIVE: {
1272                         state_info->ps_state = S_INDI_CELLULAR_OFF;
1273                 } break;
1274
1275                 default: {
1276                         s_indi_log_ex(cp_name, "Unexpected command: [0x%x]", command);
1277                         s_indi_assert_not_reached();
1278                         return TRUE;
1279                 }
1280         }
1281
1282 OUT:
1283         /* Update PS Call state */
1284         strg_vconf = tcore_server_find_storage(server, S_INDI_VCONF_STORAGE_NAME);
1285         if (state_info->ps_state != tcore_storage_get_int(strg_vconf, vconf_key)) {
1286                 tcore_storage_set_int(strg_vconf, vconf_key, state_info->ps_state);
1287                 s_indi_log_ex(cp_name, "PS Call status - [%s]", (state_info->ps_state == S_INDI_CELLULAR_CONNECTED ? "CONNECTED"
1288                                                 : (state_info->ps_state == S_INDI_CELLULAR_OFF ? "DISCONNECTED"
1289                                                 : (state_info->ps_state == S_INDI_CELLULAR_USING ? "IN USE" : "UNKNOWN"))));
1290         }
1291
1292         return TRUE;
1293 }
1294
1295 enum tcore_hook_return s_indi_on_hook_voice_call_status(Server *server, CoreObject *source,
1296                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data)
1297 {
1298         TcorePlugin *indi_plugin = user_data;
1299         s_indi_private_info *priv_info = __s_indi_get_priv_info(indi_plugin);
1300         const char *cp_name = NULL;
1301         s_indi_cp_state_info_type *state_info = NULL;
1302
1303         GHashTableIter iter;
1304         gpointer key, value;
1305
1306         S_INDI_NOT_USED(data_len);
1307         S_INDI_NOT_USED(data);
1308
1309         CORE_OBJECT_CHECK_RETURN(source, CORE_OBJECT_TYPE_CALL, TCORE_HOOK_RETURN_CONTINUE);
1310
1311         /* Update all modem states */
1312         g_hash_table_iter_init(&iter, priv_info->state_info);
1313         while (g_hash_table_iter_next (&iter, &key, &value)) {
1314                 cp_name = key;
1315                 state_info = value;
1316
1317                 (void)__s_indi_handle_voice_call_status(server, source, command,
1318                                 cp_name, state_info);
1319         }
1320
1321         return TCORE_HOOK_RETURN_CONTINUE;
1322 }
1323
1324 enum tcore_hook_return s_indi_on_hook_modem_plugin_added(Server *server, CoreObject *source,
1325                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data)
1326 {
1327         s_indi_assert(NULL != data);
1328         s_indi_assert(NULL != user_data);
1329
1330         S_INDI_NOT_USED(server);
1331         S_INDI_NOT_USED(source);
1332         S_INDI_NOT_USED(command);
1333         S_INDI_NOT_USED(data_len);
1334
1335         __s_indi_add_modem_plugin(user_data, data);
1336
1337         return TCORE_HOOK_RETURN_CONTINUE;
1338 }
1339
1340 enum tcore_hook_return s_indi_on_hook_modem_plugin_removed(Server *server, CoreObject *source,
1341                 enum tcore_notification_command command, unsigned int data_len, void *data, void *user_data)
1342 {
1343         s_indi_assert(NULL != data);
1344         s_indi_assert(NULL != user_data);
1345
1346         S_INDI_NOT_USED(server);
1347         S_INDI_NOT_USED(source);
1348         S_INDI_NOT_USED(command);
1349         S_INDI_NOT_USED(data_len);
1350
1351         __s_indi_remove_modem_plugin(user_data, data);
1352
1353         return TCORE_HOOK_RETURN_CONTINUE;
1354 }
1355
1356 gboolean s_indi_init(TcorePlugin *plugin)
1357 {
1358         Server *server = NULL;
1359         s_indi_private_info *priv_info = NULL;
1360
1361         priv_info = s_indi_malloc0(sizeof(*priv_info));
1362         if (tcore_plugin_link_user_data(plugin, priv_info) != TCORE_RETURN_SUCCESS) {
1363                 err("Failed to link private data");
1364                 s_indi_free(priv_info);
1365                 return FALSE;
1366         }
1367
1368         server = tcore_plugin_ref_server(plugin);
1369
1370         /* Initialize SIPC counter */
1371         priv_info->msg_id.id_current = S_INDI_SIPC_ITER_START - S_INDI_ONE;
1372         priv_info->msg_id.id_start = S_INDI_SIPC_ITER_START;
1373         priv_info->msg_id.id_end = S_INDI_SIPC_ITER_END;
1374
1375         /* Initialize VCONF => CP_NAME mapping */
1376         priv_info->vconf_info = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, s_indi_free_func);
1377
1378         /* Initialize State Information */
1379         priv_info->state_info = g_hash_table_new_full(g_str_hash, g_str_equal, s_indi_free_func, __s_indi_state_info_value_destroy_notification);
1380
1381         if (priv_info->state_info == NULL
1382                 || priv_info->vconf_info == NULL) {
1383                 err("Memory allocation problem! Bailing Out");
1384                 goto OUT;
1385         }
1386
1387         priv_info->b_pm_lock = FALSE;
1388
1389         /* Register vconf key callbacks */
1390         __s_indi_register_vconf_key(STORAGE_KEY_PM_STATE, plugin, NULL);
1391
1392         /* Server Hooks*/
1393         tcore_server_add_notification_hook(server, TNOTI_MODEM_POWER, s_indi_on_hook_modem_power, plugin);
1394         tcore_server_add_notification_hook(server, TNOTI_PS_CALL_STATUS, s_indi_on_hook_ps_call_status, plugin);
1395         tcore_server_add_notification_hook(server, TNOTI_NETWORK_REGISTRATION_STATUS, s_indi_on_hook_net_register, plugin);
1396         tcore_server_add_notification_hook(server, TNOTI_SIM_STATUS, s_indi_on_hook_sim_init, plugin);
1397
1398         /* For 2G PS suspend/resume */
1399         tcore_server_add_notification_hook(server, TNOTI_CALL_STATUS_IDLE, s_indi_on_hook_voice_call_status, plugin);
1400         tcore_server_add_notification_hook(server, TNOTI_CALL_STATUS_DIALING, s_indi_on_hook_voice_call_status, plugin);
1401         tcore_server_add_notification_hook(server, TNOTI_CALL_STATUS_INCOMING, s_indi_on_hook_voice_call_status, plugin);
1402         tcore_server_add_notification_hook(server, TNOTI_CALL_STATUS_ACTIVE, s_indi_on_hook_voice_call_status, plugin);
1403
1404         /* For new Modems */
1405         tcore_server_add_notification_hook(server, TNOTI_SERVER_ADDED_MODEM_PLUGIN, s_indi_on_hook_modem_plugin_added, plugin);
1406         tcore_server_add_notification_hook(server, TNOTI_SERVER_REMOVED_MODEM_PLUGIN, s_indi_on_hook_modem_plugin_removed, plugin);
1407
1408         /* Add existing Modems */
1409         __s_indi_refresh_modems(plugin);
1410
1411         return TRUE;
1412
1413 OUT:
1414         s_indi_deinit(plugin);
1415         return FALSE;
1416 }
1417
1418 void s_indi_deinit(TcorePlugin *plugin)
1419 {
1420         Server *server = NULL;
1421         GList *iter;
1422         s_indi_cp_state_info_type *state_info = NULL;
1423         TcorePlugin *modem_plugin = NULL;
1424         s_indi_private_info *priv_info = __s_indi_get_priv_info(plugin);
1425
1426         /* Remove Hooks */
1427         server = tcore_plugin_ref_server(plugin);
1428         tcore_server_remove_notification_hook(server, s_indi_on_hook_modem_power);
1429         tcore_server_remove_notification_hook(server, s_indi_on_hook_ps_call_status);
1430         tcore_server_remove_notification_hook(server, s_indi_on_hook_net_register);
1431         tcore_server_remove_notification_hook(server, s_indi_on_hook_sim_init);
1432         tcore_server_remove_notification_hook(server, s_indi_on_hook_voice_call_status);
1433         tcore_server_remove_notification_hook(server, s_indi_on_hook_modem_plugin_added);
1434         tcore_server_remove_notification_hook(server, s_indi_on_hook_modem_plugin_removed);
1435
1436         /* Remove key callback */
1437         __s_indi_unregister_vconf_key(STORAGE_KEY_PM_STATE, plugin, NULL);
1438
1439         /* Destroy all watched modems */
1440         iter = g_hash_table_get_values(priv_info->state_info);
1441         while (iter) {
1442                 state_info = iter->data;
1443                 modem_plugin = tcore_object_ref_plugin(state_info->co_ps);
1444                 __s_indi_remove_modem_plugin(plugin, modem_plugin);
1445
1446                 iter = g_list_delete_link(iter, iter);
1447         }
1448
1449         /* Decrement hash table reference */
1450         g_hash_table_destroy(priv_info->state_info);
1451         g_hash_table_destroy(priv_info->vconf_info);
1452
1453         /* Finalize */
1454         s_indi_free(priv_info);
1455         tcore_plugin_link_user_data(plugin, NULL);
1456 }