Code Sync up from tizen_2.4
[platform/core/telephony/tel-plugin-packetservice.git] / src / service.c
1 /*
2  * PacketService Control Module
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: DongHoo Park <donghoo.park@samsung.com>
7  *          Arun Shukla <arun.shukla@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 #include "ps.h"
24 #include "generated-code.h"
25
26 #include <core_object.h>
27 #include <co_ps.h>
28 #include <co_context.h>
29 #include <storage.h>
30
31 #define PROP_DEFAULT    FALSE
32 #define PROP_DEFAULT_STR   NULL
33 #define BOOL2STRING(a)  ((a==TRUE) ? ("TRUE"):("FALSE"))
34
35 #define TIMEOUT_DEFAULT         5
36 #define TIMEOUT_MAX                     1800
37
38
39 static void __ps_service_emit_property_changed_signal(ps_service_t *service);
40 static void __ps_service_emit_context_added_signal(ps_service_t *service, gpointer context);
41 static void __ps_service_emit_context_removed_signal(ps_service_t *service, gpointer context);
42 static void _ps_service_setup_interface(PacketServiceService *service, ps_service_t *service_data);
43
44 static char *   __ps_service_act2string(enum telephony_network_access_technology act);
45 static gboolean __ps_service_check_connection_option(gpointer service, gpointer context);
46 static int __ps_service_connetion_timeout_handler(alarm_id_t alarm_id, void *context);
47
48 void __remove_service_handler(gpointer data)
49 {
50         ps_service_t *service = data;
51
52         dbg("Entered");
53         if(!service){
54                 dbg("Service is Null");
55                 return;
56         }
57
58         /*Need to remove the compelete hash table*/
59         g_hash_table_remove_all(service->contexts);
60
61         /*Need to UNexport and Unref the master Object */
62         if(service->if_obj){
63                 g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(service->if_obj));
64                 g_object_unref(service->if_obj);
65                 service->if_obj = NULL;
66         }
67
68         /*Need to free the memory of the internal structure*/
69         g_free(service->path);
70         g_free(service);
71
72         dbg("Exiting");
73         return;
74 }
75
76 static void __ps_service_emit_property_changed_signal(ps_service_t *service)
77 {
78         GVariant *gv = NULL;
79         GVariantBuilder property;
80
81         ps_dbg_ex_co(_ps_service_ref_co_network(service), "get service properties");
82
83         gv = _ps_service_get_properties(service, &property);
84         packet_service_service_emit_property_changed(service->if_obj, gv);
85
86         dbg("Exiting");
87         return;
88 }
89
90 static void __ps_service_emit_context_added_signal(ps_service_t *service, gpointer context)
91 {
92         GVariant *gv = NULL;
93         GVariantBuilder property;
94
95         ps_dbg_ex_co(_ps_service_ref_co_network(service), "get service properties");
96
97         gv = _ps_context_get_properties(context, &property);
98         packet_service_service_emit_context_added(service->if_obj, gv);
99
100         dbg("Exiting");
101         return;
102 }
103
104 static void __ps_service_emit_context_removed_signal(ps_service_t *service, gpointer context)
105 {
106         ps_context_t *pscontext = context;
107
108         dbg("Entered");
109         packet_service_service_emit_context_removed(service->if_obj, pscontext->path);
110
111         dbg("Exiting");
112         return;
113 }
114
115 static char *__ps_service_act2string(enum telephony_network_access_technology act)
116 {
117         switch (act) {
118                 case NETWORK_ACT_GSM:
119                 case NETWORK_ACT_GPRS:
120                 case NETWORK_ACT_EGPRS:
121                 case NETWORK_ACT_UMTS:
122                 case NETWORK_ACT_GSM_UTRAN:
123                         return "GSM";
124                 case NETWORK_ACT_IS95A:
125                 case NETWORK_ACT_IS95B:
126                 case NETWORK_ACT_CDMA_1X:
127                 case NETWORK_ACT_EVDO_REV0:
128                 case NETWORK_ACT_CDMA_1X_EVDO_REV0:
129                 case NETWORK_ACT_EVDO_REVA:
130                 case NETWORK_ACT_CDMA_1X_EVDO_REVA:
131                 case NETWORK_ACT_EVDV:
132                         return "CDMA";
133                 case NETWORK_ACT_LTE:
134                         return "LTE";
135                 case NETWORK_ACT_UNKNOWN:
136                 default:
137                         return "unknown";
138         }
139
140         return NULL;
141 }
142
143 static gboolean __ps_service_check_connection_option(gpointer object, gpointer context)
144 {
145         gboolean b_connect = TRUE;
146         gboolean power = FALSE, sim = FALSE, data = FALSE, flight = FALSE, nw_ops = FALSE;
147         gboolean profile_reset = FALSE;
148
149         enum co_context_role role = CONTEXT_ROLE_UNKNOWN;
150         gint ps_mode;
151         guchar hook_flag;
152
153         ps_service_t *service = object;
154         ps_modem_t *modem = _ps_service_ref_modem(service);
155         CoreObject *co_context = context;
156         CoreObject *co_network = _ps_service_ref_co_network(service);
157
158         role = tcore_context_get_role(co_context);
159         if(service->roaming){
160                 b_connect &=_ps_modem_get_data_roaming_allowed(modem);
161         }
162
163         sim = _ps_modem_get_sim_init(modem);
164         data = _ps_modem_get_data_allowed(modem);
165         flight = _ps_modem_get_flght_mode(modem);
166         hook_flag = _ps_modem_get_hook_flag(modem);
167         profile_reset = _ps_modem_get_reset_profile(modem);
168         if(hook_flag != PS_NO_PENDING_REQUEST)
169                 nw_ops = TRUE;
170         if(PS_MODEM_STATE_ONLINE == _ps_modem_get_power(modem))
171                 power = TRUE;
172
173         b_connect &= power;
174         b_connect &= sim;
175
176 #if defined(TIZEN_SUPPORT_MMS_CONNECT_FORCE)
177                 ps_dbg_ex_co(co_network, "csc runtime feature enabled");
178                 if(role != CONTEXT_ROLE_MMS && role != CONTEXT_ROLE_PREPAID_MMS){
179                         b_connect &= data;
180                 } else {
181                         char *tmp_apn = NULL;
182                         tmp_apn = tcore_context_get_apn(co_context);
183                         dbg("csc runtime feature is enabled: apn[%s]", tmp_apn);
184                         if(ps_feature_get_bool(PS_FEATURE_OPERATOR_SKT)) {
185                                 if(data)
186                                         tcore_context_set_apn(co_context, "web.sktelecom.com");
187                                 else
188                                         tcore_context_set_apn(co_context, "mmsonly.sktelecom.com");
189                         }
190                 }
191 #else
192         if (role == CONTEXT_ROLE_IMS || role == CONTEXT_ROLE_IMS_EMERGENCY) {
193                 dbg("Do not check data allowed value in case of IMS type");
194         } else {
195                 ps_dbg_ex_co(co_network, "csc runtime feature disabled");
196                 b_connect &= data;
197         }
198 #endif
199
200         b_connect &= !flight;
201         b_connect &= !nw_ops;
202         b_connect &= !service->restricted;
203         b_connect &= !profile_reset;
204 #ifndef TIZEN_PS_FORCE_ATTACH_DETACH
205         b_connect &= service->ps_attached;
206 #endif
207         ps_mode = _ps_modem_get_psmode(modem);
208
209
210         if(service->initial_pdp_conn == FALSE) {
211                 int wifi_state = PS_WIFI_STATE_OFF;
212                 Server *s = NULL;
213                 Storage *strg = NULL;
214
215                 s = tcore_plugin_ref_server(service->plg);
216                 strg = tcore_server_find_storage(s, "vconf");
217                 wifi_state = tcore_storage_get_int(strg, KEY_WIFI_STATE);
218                 if(wifi_state == PS_WIFI_STATE_CONNECTED) {
219                         if (service->wifi_connected_checked == FALSE) {
220                                 ps_dbg_ex_co(co_network, "DO NOT set PDP retry timer when WiFi connected but PDP never been connected yet.");
221                                 b_connect &= FALSE;
222                                 service->wifi_connected_checked = TRUE;
223                         } else {
224                                 ps_dbg_ex_co(co_network, "Wifi connected state was already checked.");
225                         }
226                 }
227         }
228         ps_dbg_ex_co(co_network, "b_connect(%d), power(%d), sim init(%d), data allowed(%d), flight mode(%d) restricted(%d) ps_attached(%d), ps_mode(%d), fook_flag(%d)",
229                 b_connect, power, sim, data, flight, service->restricted, service->ps_attached, ps_mode, hook_flag);
230
231         return b_connect;
232 }
233
234 static int __ps_service_connetion_timeout_handler(alarm_id_t alarm_id, void *context)
235 {
236         int rv = 0;
237         ps_service_t *service = _ps_context_ref_service(context);
238         if(service == NULL) {
239                 err("service is NULL!!!");
240                 return rv;
241         }
242
243         if (service->timer_src > 0) {
244                 dbg("remove connection retry timer (%d)", service->timer_src);
245                 alarmmgr_remove_alarm(service->timer_src);
246                 service->timer_src = 0;
247         }
248         rv = _ps_service_activate_context(service, context);
249         ps_dbg_ex_co(_ps_service_ref_co_network(service), "return rv(%d)", rv);
250         return rv;
251 }
252
253 static void __ps_service_set_attach_apn(ps_service_t *service)
254 {
255         GHashTableIter iter;
256         gpointer key, ps_context;
257         CoreObject *co_context;
258         gboolean attach_apn = FALSE;
259         enum co_context_role role;
260
261         g_hash_table_iter_init(&iter, service->contexts);
262         while (g_hash_table_iter_next(&iter, &key, &ps_context) == TRUE) {
263                 co_context = _ps_context_ref_co_context(ps_context);
264                 role = tcore_context_get_role(co_context);
265                 attach_apn = tcore_context_get_attach_apn(co_context);
266                 if (attach_apn) {
267                         dbg("Set 'Attach APN' [%p]", co_context);
268                         if (role != CONTEXT_ROLE_INTERNET)
269                                 _ps_context_set_only_attach(ps_context, TRUE);
270                         tcore_ps_define_context(service->co_ps, co_context, NULL);
271                 }
272         }
273 }
274
275 gpointer _ps_service_create_service(GDBusConnection *conn, TcorePlugin *p, gpointer p_modem,
276                 CoreObject *co_network, CoreObject *co_ps, gchar* path)
277 {
278         PacketServiceService *service;
279         GError *error = NULL;
280         ps_service_t *new_service;
281
282         ps_dbg_ex_co(co_network, "service object create");
283         g_return_val_if_fail(conn != NULL, NULL);
284         g_return_val_if_fail(p_modem != NULL, NULL);
285
286         /*creating the master object for the interface com.tcore.ps.modem*/
287         service = packet_service_service_skeleton_new();
288
289         /*Initializing the modem list for internal referencing*/
290         new_service = g_try_malloc0(sizeof(ps_service_t));
291         if(NULL == new_service){
292                 ps_err_ex_co(co_network, "Unable to allocate memory for master");
293                 goto FAILURE;
294         }
295
296         new_service->conn = conn;
297         new_service->plg = p;
298         new_service->p_modem = p_modem;
299         new_service->co_network = co_network;
300         new_service->co_ps = co_ps;
301         new_service->path = g_strdup(path);
302         new_service->if_obj = service;
303         new_service->contexts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
304
305         /*exporting the interface object to the path mention for master*/
306         if(TRUE != g_dbus_interface_skeleton_export((G_DBUS_INTERFACE_SKELETON(service)),       conn, path, &error)) {
307                 ps_err_ex_co(co_network, "Failed to export interaface with message [%s] & ID[%d] ", error->message, error->code);
308                 goto FAILURE;
309         }
310
311         _ps_hook_co_network_event(new_service);
312         _ps_get_co_network_values(new_service);
313         _ps_hook_co_ps_event(new_service);
314
315         /*Setting up the interface for the service */
316         _ps_service_setup_interface(service, new_service);
317
318         new_service->connection_timeout = TIMEOUT_DEFAULT;
319         ps_dbg_ex_co(co_network, "Successfully Created the service");
320         return new_service;
321
322 FAILURE:
323         /*To Do: Handle failure case*/
324         g_free(new_service);
325         g_assert_no_error (error);
326         return NULL;
327 }
328
329 gboolean _ps_service_ref_context(gpointer object, gpointer context)
330 {
331         gpointer tmp = NULL;
332         gchar *s_path = NULL;
333         ps_service_t *service = object;
334         CoreObject *co_network = NULL;
335
336         dbg("service refer to context");
337         g_return_val_if_fail(service != NULL, FALSE);
338
339         co_network = _ps_service_ref_co_network(service);
340         s_path = _ps_context_ref_path(context);
341         tmp = g_hash_table_lookup(service->contexts, s_path);
342         if (tmp != NULL) {
343                 ps_dbg_ex_co(co_network, "context(%p) already existed", tmp);
344                 return FALSE;
345         }
346
347         _ps_context_set_service(context, service);
348         tcore_ps_add_context(service->co_ps, (CoreObject *) _ps_context_ref_co_context(context));
349         g_hash_table_insert(service->contexts, g_strdup(s_path), context);
350
351         ps_dbg_ex_co(co_network, "context(%p) insert to hash", context);
352         __ps_service_emit_context_added_signal(service, context);
353
354         //_ps_service_connect_default_context(service);
355         return TRUE;
356 }
357
358 gboolean _ps_service_ref_contexts(gpointer object, GHashTable *contexts, gchar *operator)
359 {
360         GHashTableIter iter;
361         gpointer key, value;
362         ps_service_t *service = object;
363         gboolean ret = TRUE;
364         int rv;
365         CoreObject *co_network = NULL;
366
367         dbg("service refer to contexts");
368         g_return_val_if_fail(service != NULL, FALSE);
369
370         co_network = _ps_service_ref_co_network(service);
371         g_hash_table_iter_init(&iter, contexts);
372         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
373                 gchar *s_path = NULL;
374                 gpointer tmp = NULL;
375                 gboolean f_awo = FALSE;
376
377                 s_path = _ps_context_ref_path(value);
378                 tmp = g_hash_table_lookup(service->contexts, s_path);
379                 if (tmp != NULL) {
380                         ps_dbg_ex_co(co_network, "context(%p) already existed", tmp);
381                         continue;
382                 }
383
384                 _ps_context_set_service(value, service);
385                 tcore_ps_add_context(service->co_ps, (CoreObject *) _ps_context_ref_co_context(value));
386                 g_hash_table_insert(service->contexts, g_strdup(s_path), value);
387
388                 ps_dbg_ex_co(co_network, "context(%p) insert to hash", value);
389                 __ps_service_emit_context_added_signal(service, value);
390
391                 f_awo = _ps_context_get_alwayson_enable(value);
392                 if(f_awo){
393                         rv = _ps_service_define_context(service, value);
394                         ps_dbg_ex_co(co_network, "return rv(%d)", rv);
395                 }
396         }
397
398         _ps_update_cellular_state_key(service);
399         //_ps_service_connect_default_context(service);
400         return ret;
401 }
402
403 gboolean _ps_service_unref_context(gpointer object, gpointer context)
404 {
405         ps_service_t *service = object;
406
407         dbg("service unref contexts");
408         g_return_val_if_fail(service != NULL, FALSE);
409         g_return_val_if_fail(context != NULL, FALSE);
410
411         ps_dbg_ex_co(_ps_service_ref_co_network(service), "remove context(%p) from service(%p)", context, service);
412         tcore_ps_remove_context(service->co_ps, (CoreObject *) _ps_context_ref_co_context(context));
413         g_hash_table_remove(service->contexts, _ps_context_ref_path(context));
414         __ps_service_emit_context_removed_signal(service, context);
415
416         return TRUE;
417 }
418
419 gboolean _ps_service_get_properties_handler(gpointer object, GVariantBuilder *properties)
420 {
421         ps_service_t *service = object;
422
423         dbg("get service properties");
424         g_return_val_if_fail(service != NULL, FALSE);
425         g_return_val_if_fail(properties != NULL, FALSE);
426
427         g_variant_builder_open(properties, G_VARIANT_TYPE("a{ss}"));
428         g_variant_builder_add(properties, "{ss}", "path", service->path);
429         g_variant_builder_add(properties, "{ss}", "ps_attached", BOOL2STRING(service->ps_attached));
430         g_variant_builder_add(properties, "{ss}", "roaming", BOOL2STRING(service->roaming));
431         g_variant_builder_add(properties, "{ss}", "act", __ps_service_act2string(service->act));
432         g_variant_builder_close(properties);
433
434         dbg("Exiting");
435         return TRUE;
436 }
437
438 GVariant * _ps_service_get_properties(gpointer object, GVariantBuilder *properties)
439 {
440         ps_service_t *service = object;
441
442         dbg("get service properties ");
443         g_return_val_if_fail(service != NULL, FALSE);
444         g_return_val_if_fail(properties != NULL, FALSE);
445
446         g_variant_builder_init(properties, G_VARIANT_TYPE("a{ss}"));
447
448         g_variant_builder_add(properties, "{ss}", "path", service->path);
449         g_variant_builder_add(properties, "{ss}", "ps_attached", BOOL2STRING(service->ps_attached));
450         g_variant_builder_add(properties, "{ss}", "roaming", BOOL2STRING(service->roaming));
451         g_variant_builder_add(properties, "{ss}", "act", __ps_service_act2string(service->act));
452
453         dbg("Exiting");
454         return g_variant_builder_end(properties);
455 }
456
457 gchar* _ps_service_ref_path(gpointer object)
458 {
459         ps_service_t *service = object;
460         g_return_val_if_fail(service != NULL, NULL);
461
462         return service->path;
463 }
464
465 gpointer _ps_service_ref_plugin(gpointer object)
466 {
467         ps_service_t *service = object;
468         g_return_val_if_fail(service != NULL, NULL);
469
470         return service->plg;
471 }
472
473 gpointer _ps_service_ref_co_network(gpointer object)
474 {
475         ps_service_t *service = object;
476         g_return_val_if_fail(service != NULL, NULL);
477
478         return service->co_network;
479 }
480
481 gpointer _ps_service_ref_co_ps(gpointer object)
482 {
483         ps_service_t *service = object;
484         g_return_val_if_fail(service != NULL, NULL);
485
486         return service->co_ps;
487 }
488
489 gpointer _ps_service_ref_modem(gpointer object)
490 {
491         ps_service_t *service = object;
492         g_return_val_if_fail(service != NULL, NULL);
493
494         return service->p_modem;
495 }
496
497 gboolean _ps_service_set_context_info(gpointer object, struct tnoti_ps_pdp_ipconfiguration *devinfo)
498 {
499         GSList* contexts = NULL;
500         ps_service_t *service = object;
501         CoreObject *co_context = NULL;
502
503         dbg("set context info");
504         g_return_val_if_fail(service != NULL, FALSE);
505
506         contexts = tcore_ps_ref_context_by_id(service->co_ps, devinfo->context_id);
507         if (!contexts) {
508                 ps_dbg_ex_co(_ps_service_ref_co_network(service), "fail to ref context by cid.");
509                 return FALSE;
510         }
511
512         while (contexts) {
513                 co_context = contexts->data;
514                 if (!co_context) {
515                         contexts = contexts->next;
516                         continue;
517                 }
518
519                 tcore_context_set_devinfo(co_context, devinfo);
520
521                 contexts = contexts->next;
522         }
523
524         return TRUE;
525 }
526
527 int _ps_service_define_context(gpointer object, gpointer context)
528 {
529         ps_service_t *service = object;
530         CoreObject *co_context = NULL;
531         gboolean b_connect = TRUE;
532
533         dbg("define context(%p)", context);
534         g_return_val_if_fail(service != NULL, FALSE);
535
536         co_context = (CoreObject *)_ps_context_ref_co_context(context);
537
538         b_connect = __ps_service_check_connection_option(service, co_context);
539         if(!b_connect)
540                 return TCORE_RETURN_EPERM;
541
542         return tcore_ps_define_context(service->co_ps, co_context, NULL);
543 }
544
545 int _ps_service_activate_context(gpointer object, gpointer context)
546 {
547         ps_service_t *service = object;
548         ps_modem_t *modem = NULL;
549         CoreObject *co_context = NULL;
550         gboolean b_connect = TRUE;
551         gboolean ps_defined;
552         int ret = TCORE_RETURN_FAILURE;
553         int default_data_subs = 1;
554         ps_subs_type subs_type = 1;
555         Server *s = NULL;
556         static Storage *strg;
557         CoreObject *co_network = NULL;
558
559         dbg("activate context(%p)", context);
560         g_return_val_if_fail(service != NULL, FALSE);
561
562         s = tcore_plugin_ref_server(_ps_service_ref_plugin(service));
563         strg = tcore_server_find_storage(s, "vconf");
564
565         co_network = _ps_service_ref_co_network(service);
566         modem = _ps_service_ref_modem(service);
567         if(modem->hook_flag != PS_NO_PENDING_REQUEST){
568                 ps_dbg_ex_co(co_network, "Pending request present in queue with flag %x", modem->hook_flag);
569                 return TCORE_RETURN_FAILURE;
570         }
571
572         /* Check for default data subscription value if matchs for modem then only activate */
573         subs_type = _ps_modem_get_subs_type(modem);
574
575         default_data_subs = tcore_storage_get_int(strg, STORAGE_KEY_TELEPHONY_DUALSIM_DEFAULT_DATA_SERVICE_INT);
576         if ((default_data_subs != -1) && ( default_data_subs != (int)subs_type)) {
577                 ps_warn_ex_co(co_network, "activation  for only [SIM%d] selected by Setting", default_data_subs + 1);
578                 return TCORE_RETURN_FAILURE;
579         }
580
581         co_context = (CoreObject *)_ps_context_ref_co_context(context);
582
583         b_connect = __ps_service_check_connection_option(service, co_context);
584         if(!b_connect)
585                 return TCORE_RETURN_EPERM;
586
587         ps_defined = _ps_context_get_ps_defined(context);
588         if(!ps_defined) {
589                 ps_dbg_ex_co(co_network, "pdp profile is not defined yet, define first. ");
590                 ret = tcore_ps_define_context(service->co_ps, co_context, NULL);
591         }
592         else {
593                 ps_dbg_ex_co(co_network, "pdp profile is defined, activate context. ");
594                 ret = tcore_ps_activate_context(service->co_ps, co_context, NULL);
595         }
596
597         return ret;
598 }
599
600 gboolean _ps_service_deactivate_context(gpointer object, gpointer context)
601 {
602         ps_service_t *service = object;
603         CoreObject *co_context = NULL;
604
605         g_return_val_if_fail(service != NULL, FALSE);
606         dbg("deactivate context(%p)", context);
607         co_context = (CoreObject *)_ps_context_ref_co_context(context);
608
609         return tcore_ps_deactivate_context(service->co_ps, co_context, NULL);
610 }
611
612 void _ps_service_set_retry_timeout_value(gpointer object, int value)
613 {
614         ps_service_t *service = object;
615         g_return_if_fail(service != NULL);
616
617         service->connection_timeout = value;
618         dbg("current timeout (%d)", service->connection_timeout);
619         return;
620 }
621
622 void _ps_service_connection_timer(gpointer object, gpointer context)
623 {
624         int result = 0;
625         gboolean f_awo = FALSE;
626         ps_service_t *service = object;
627
628         g_return_if_fail(service != NULL);
629
630         f_awo = _ps_context_get_alwayson_enable(context);
631         if(!f_awo)
632                 return;
633
634         if (service->timer_src > 0) {
635                 warn("remove connection retry timer (%d)", service->timer_src);
636                 alarmmgr_remove_alarm(service->timer_src);
637                 service->timer_src = 0;
638         }
639         result = alarmmgr_add_alarm_withcb(ALARM_TYPE_VOLATILE, (time_t)(service->connection_timeout),
640                         0, __ps_service_connetion_timeout_handler, context, &(service->timer_src));
641         if (result != ALARMMGR_RESULT_SUCCESS) {
642                 err("Failed to add alarm(%d)", result);
643                 return;
644         }
645
646         dbg("cellular service timer started timer src(%d), timeout(%d)", service->timer_src, service->connection_timeout);
647         service->connection_timeout = (service->connection_timeout)*2;
648         if(service->connection_timeout >= TIMEOUT_MAX)
649                 service->connection_timeout = TIMEOUT_MAX;
650
651         return;
652 }
653
654 void _ps_service_reset_connection_timer(gpointer context)
655 {
656         gboolean f_awo = FALSE;
657         ps_service_t *service = NULL;
658
659         f_awo = _ps_context_get_alwayson_enable(context);
660         if(!f_awo)
661                 return;
662
663         service = _ps_context_ref_service(context);
664         if(service == NULL) {
665                 err("service is NULL!!!");
666                 return;
667         }
668         service->connection_timeout = TIMEOUT_DEFAULT;
669
670         if (service->timer_src > 0) {
671                 warn("remove connection retry timer (%d)", service->timer_src);
672                 alarmmgr_remove_alarm(service->timer_src);
673                 service->timer_src = 0;
674         }
675
676         return;
677 }
678
679 void _ps_service_remove_contexts(gpointer object)
680 {
681         GHashTableIter iter;
682         gpointer key, value;
683         ps_service_t *service = object;
684
685         dbg("service remove all contexts");
686         g_return_if_fail(service != NULL);
687
688         g_hash_table_iter_init(&iter, service->contexts);
689         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
690                 gpointer co_context = NULL;
691
692                 ps_dbg_ex_co(_ps_service_ref_co_network(service), "key(%s), value(%p) context", key, value);
693                 co_context = _ps_context_ref_co_context(value);
694
695                 _ps_service_reset_connection_timer(value);
696                 _ps_context_set_alwayson_enable(value, FALSE);
697                 _ps_service_deactivate_context(service, value);
698                 _ps_context_set_connected(value, FALSE);
699                 tcore_ps_remove_context(service->co_ps, co_context);
700                 tcore_context_free(co_context);
701
702                 __ps_service_emit_context_removed_signal(service, value);
703                 _ps_context_remove_context(value);
704         }
705
706         g_hash_table_remove_all(service->contexts);
707         return;
708 }
709
710 void _ps_service_disconnect_contexts(gpointer object)
711 {
712         GHashTableIter iter;
713         gpointer key, value;
714         ps_service_t *service = object;
715
716         dbg("service disconnect all contexts");
717         g_return_if_fail(service != NULL);
718
719         g_hash_table_iter_init(&iter, service->contexts);
720         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
721                 _ps_service_reset_connection_timer(value);
722                 _ps_service_deactivate_context(service, value);
723         }
724
725         return;
726 }
727
728 void _ps_service_disconnect_internet_mms_contexts(gpointer object)
729 {
730         GHashTableIter iter;
731         gpointer key, value;
732         ps_service_t *service = object;
733         CoreObject *co_context = NULL;
734         enum co_context_role role = CONTEXT_ROLE_UNKNOWN;
735
736         dbg("Service disconnect Internet/MMS contexts");
737         g_return_if_fail(service != NULL);
738
739         g_hash_table_iter_init(&iter, service->contexts);
740         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
741                 co_context = (CoreObject *)_ps_context_ref_co_context(value);
742                 role = tcore_context_get_role(co_context);
743
744                 /*
745                  * Deactivate following type of contexts -
746                  *      - INTERNET
747                  *      - INTERNET_PREPAID
748                  *      - MMS
749                  *      - MMS_PREPAID
750                  */
751                 switch (role) {
752                 case CONTEXT_ROLE_INTERNET:
753                 case CONTEXT_ROLE_MMS:
754                 case CONTEXT_ROLE_PREPAID_INTERNET:
755                 case CONTEXT_ROLE_PREPAID_MMS:
756                         _ps_service_reset_connection_timer(value);
757                         _ps_service_deactivate_context(service, value);
758                 break;
759
760                 default: {
761                         dbg("Need not deactivate for %d PDN type", role);
762                         continue;
763                 }
764                 }
765         }
766 }
767
768 int _ps_service_connect_default_context(gpointer object)
769 {
770         int rv = 0;
771         GHashTableIter iter;
772         gpointer key, value;
773         ps_service_t *service = object;
774
775         dbg("service connect default context");
776         g_return_val_if_fail(service != NULL, TCORE_RETURN_FAILURE);
777
778         g_hash_table_iter_init(&iter, service->contexts);
779         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
780                 gboolean f_awo = FALSE;
781                 f_awo = _ps_context_get_alwayson_enable(value);
782
783                 if(f_awo){
784                         _ps_service_reset_connection_timer(value);
785                         rv = _ps_service_activate_context(service, value);
786                         ps_dbg_ex_co(_ps_service_ref_co_network(service), "return rv(%d)", rv);
787                         break;
788                 }
789         }
790
791         return rv;
792 }
793
794 gpointer _ps_service_return_default_context(gpointer object, int svc_cat_id)
795 {
796         GHashTableIter iter;
797         gpointer key, value;
798         ps_service_t *service = object;
799
800         g_return_val_if_fail(service != NULL, NULL);
801
802         g_hash_table_iter_init(&iter, service->contexts);
803         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
804                 gboolean b_default = FALSE;
805                 b_default = _ps_context_get_default_context(value, svc_cat_id);
806
807                 if(b_default){
808                         return value;
809                 }
810         }
811
812         return NULL;
813 }
814
815 int _ps_service_update_roaming_apn(gpointer object, const char* apn_str)
816 {
817         int rv = 0;
818         GHashTableIter iter;
819         gpointer key, value;
820         ps_service_t *service = object;
821
822         g_return_val_if_fail(service != NULL, TCORE_RETURN_FAILURE);
823
824         g_hash_table_iter_init(&iter, service->contexts);
825         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
826                 CoreObject *co_context = NULL;
827                 int role = CONTEXT_ROLE_UNKNOWN;
828                 char *tmp_apn = NULL, *path = NULL;
829
830                 co_context = (CoreObject *)_ps_context_ref_co_context(value);
831                 role = tcore_context_get_role(co_context);
832                 tmp_apn = tcore_context_get_apn(co_context);
833                 path = _ps_context_ref_path(value);
834
835                 if(role == CONTEXT_ROLE_INTERNET || role == CONTEXT_ROLE_MMS) {
836                         dbg("context[%s]}, role[%d], apn[%s] -> apn[%s]", path, role, tmp_apn, apn_str);
837                         tcore_context_set_apn(co_context, apn_str);
838                         tcore_ps_deactivate_context(service->co_ps, co_context, NULL);
839                 }
840                 g_free(tmp_apn);
841         }
842         dbg("rv: %d", rv);
843         return rv;
844 }
845
846 gboolean _ps_service_processing_network_event(gpointer object, gboolean ps_attached, gboolean roaming)
847 {
848         ps_service_t *service = object;
849         CoreObject *co_network = NULL;
850         gboolean prev_roaming_status;
851         g_return_val_if_fail(service != NULL, FALSE);
852
853
854         prev_roaming_status = _ps_service_get_roaming(service);
855
856         co_network = _ps_service_ref_co_network(service);
857         _ps_service_set_ps_attached(service, ps_attached);
858         _ps_service_set_roaming(service, roaming);
859         _ps_update_cellular_state_key(service);
860         /* Need to set 'Attach APN' for 'ESM Attach' if ps_status is available */
861         if (ps_attached)
862                 __ps_service_set_attach_apn(service);
863
864         if(prev_roaming_status != _ps_service_get_roaming(service)) {
865                 gboolean roaming_allowed = FALSE;
866                 roaming_allowed = _ps_modem_get_data_roaming_allowed(service->p_modem);
867                 if(!roaming_allowed && roaming) {
868                         ps_dbg_ex_co(co_network, "Roaming allowed (%d), Roaming status (%d)", roaming_allowed, roaming);
869                         _ps_service_disconnect_contexts(service);
870                         return TRUE;
871                 }
872         }
873
874         if(service->ps_attached)
875                 _ps_service_connect_default_context(service);
876
877         return TRUE;
878 }
879
880 gboolean _ps_service_set_connected(gpointer object, gpointer cstatus, gboolean enabled)
881 {
882         GHashTableIter iter;
883         gpointer key, value;
884
885         gboolean def_awo = FALSE, b_def_conn = FALSE;
886         gpointer def_conn = NULL;
887         gpointer requested_conn = NULL;
888
889         ps_service_t *service = NULL;
890         struct tnoti_ps_call_status *call_status = NULL;
891         CoreObject * co_network;
892 //      gpointer pre_def_conn = NULL;
893
894         service = (ps_service_t *) object;
895         co_network = _ps_service_ref_co_network(service);
896         call_status = (struct tnoti_ps_call_status *)cstatus;
897
898         if(enabled && service->initial_pdp_conn == FALSE) {
899                 ps_dbg_ex_co(co_network, "Initial PDP connection.");
900                 service->initial_pdp_conn = TRUE;
901         }
902
903         g_hash_table_iter_init(&iter, service->contexts);
904         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
905                 int tmp_cid;
906                 gboolean b_tmp_def = FALSE;
907                 CoreObject *context = NULL;
908                 gpointer b_user_data = NULL;
909
910                 context = _ps_context_ref_co_context(value);
911                 tmp_cid = tcore_context_get_id(context);
912
913                 if (tmp_cid != call_status->context_id) continue;
914
915                 //if there is default context in disconnected cid, it has to retry auto connection
916                 b_tmp_def = _ps_context_get_default_context(value, CONTEXT_ROLE_INTERNET);
917                 if(!b_def_conn){
918                         b_def_conn = b_tmp_def;
919                 }
920
921                 //if disconnected connection has the user data, it is a priority connection.
922                 b_user_data = _ps_context_get_user_data(value);
923                 if(b_user_data){
924                         def_conn = value;
925                         requested_conn = b_user_data;
926                 }
927
928                 if(!enabled){
929                         gchar *ipv4 = NULL;
930
931                         ps_dbg_ex_co(co_network, "Reset socket connections.");
932
933                         tcore_ps_clear_context_id(service->co_ps, context);
934                         ipv4 = tcore_context_get_ipv4_addr(context);
935                         tcore_util_reset_ipv4_socket(tcore_context_get_ipv4_devname(context), (const char*)ipv4);
936                 }
937
938                 _ps_context_set_connected(value, enabled);
939         }
940
941         //connect to request profile
942         if(!enabled && requested_conn){
943                 ps_dbg_ex_co(co_network, "connect to request profile (%p)", requested_conn);
944                 _ps_connection_hdlr(requested_conn);
945                 _ps_service_reset_connection_timer(def_conn);
946                 _ps_context_reset_user_data(def_conn);
947                 return TRUE;
948         }
949
950         //default context and always on is true. - request to connect
951         if(!enabled){
952                 def_conn = _ps_service_return_default_context(service, CONTEXT_ROLE_INTERNET);
953                 def_awo = _ps_context_get_alwayson_enable(def_conn);
954
955                 if(!def_awo){
956                         ps_dbg_ex_co(co_network, "there is no always on connection");
957                         return TRUE;
958                 }
959
960                 //always on TRUE and default connection - NORMAL RETRY
961                 //always on TRUE and no default connection - WAIT 5 Secs for retry from application
962                 if(b_def_conn){
963                         //retry connection
964                         _ps_service_connection_timer(service, def_conn);
965                 }
966                 else{
967
968                         //disconnect from user intention
969 #if defined(CONNECT_DEFAULT_CONNECTION_WITHOUT_TIMER)
970                         if(call_status->result == 2000) {
971                                 ps_dbg_ex_co(co_network, "user intended disconnect / connect default connection without timer");
972                                 __ps_service_connetion_timeout_handler(service->timer_src, def_conn);
973                                 return TRUE;
974                         }
975 #endif
976                         //with unexpected disconnection from network/me
977                         _ps_service_set_retry_timeout_value(service, TIMEOUT_DEFAULT);
978                         _ps_service_connection_timer(service, def_conn);
979                 }
980
981         }
982
983         return TRUE;
984 }
985
986 void _ps_service_set_ps_defined(gpointer *object, gboolean value, int cid)
987 {
988         ps_service_t *service = (ps_service_t*)object;
989         GHashTableIter iter;
990         gpointer key, ps_context;
991         CoreObject *co_network;
992         CoreObject *co_context;
993         unsigned char context_id;
994
995         g_return_if_fail(service != NULL);
996
997         co_network = _ps_service_ref_co_network(service);
998         g_hash_table_iter_init(&iter, service->contexts);
999         while (g_hash_table_iter_next(&iter, &key, &ps_context) == TRUE) {
1000                 co_context = _ps_context_ref_co_context(ps_context);
1001                 context_id = tcore_context_get_id(co_context);
1002                 if (context_id == cid) {
1003                         gboolean b_only_attach;
1004                         /* Set 'ps_defined' */
1005                         _ps_context_set_ps_defined(ps_context, value);
1006
1007                         b_only_attach = _ps_context_get_only_attach(ps_context);
1008                         if (b_only_attach) {
1009                                 dbg("Do not activate for only attach apn");
1010                                 _ps_context_set_only_attach(ps_context, FALSE);
1011                                 break;
1012                         }
1013
1014                         /* Activate if define is completed */
1015                         if (value) {
1016                                 ps_dbg_ex_co(co_network, "define is complete, activate context for cid(%d)", cid);
1017                                 if (_ps_service_activate_context(service, ps_context)
1018                                                 == TCORE_RETURN_SUCCESS) {
1019                                         dbg("Successful activate context");
1020                                         tcore_ps_set_cid_active(service->co_ps, cid, TRUE);
1021                                 }
1022                         }
1023                         break;
1024                 }
1025         }
1026
1027         return;
1028 }
1029
1030 gboolean _ps_service_set_ps_attached(gpointer object, gboolean value)
1031 {
1032         ps_service_t *service = object;
1033         g_return_val_if_fail(service != NULL, FALSE);
1034
1035         service->ps_attached = value;
1036         ps_dbg_ex_co(_ps_service_ref_co_network(service), "service(%p) ps_attached(%d)", service, service->ps_attached);
1037         __ps_service_emit_property_changed_signal(service);
1038
1039         return TRUE;
1040 }
1041
1042 gboolean _ps_service_get_restricted(gpointer object)
1043 {
1044         ps_service_t *service = object;
1045         g_return_val_if_fail(service != NULL, FALSE);
1046
1047         return service->restricted;
1048 }
1049
1050 gboolean _ps_service_set_restricted(gpointer object, gboolean value)
1051 {
1052         ps_service_t *service = object;
1053         g_return_val_if_fail(service != NULL, FALSE);
1054
1055         service->restricted = value;
1056         ps_dbg_ex_co(_ps_service_ref_co_network(service), "service(%p) restricted(%d)", service, service->restricted);
1057
1058         _ps_update_cellular_state_key(service);
1059         return TRUE;
1060 }
1061
1062 gboolean _ps_service_set_number_of_pdn_cnt(gpointer object, gchar *operator)
1063 {
1064         int rv = 0;
1065         int num_of_pdn = 0;
1066         ps_service_t *service = object;
1067         g_return_val_if_fail(service != NULL, FALSE);
1068         ps_dbg_ex_co(_ps_service_ref_co_network(service), "Entered");
1069         num_of_pdn = _ps_context_get_number_of_pdn(operator, _ps_modem_ref_cp_name(_ps_service_ref_modem(object)));
1070         rv = tcore_ps_set_num_of_pdn(service->co_ps, num_of_pdn);
1071
1072         if(rv != TCORE_RETURN_SUCCESS){
1073                 ps_dbg_ex_co(_ps_service_ref_co_network(service), "error to get maximum number of pdn");
1074         }
1075         dbg("Exiting");
1076         return TRUE;
1077 }
1078
1079 gboolean _ps_service_get_roaming(gpointer object)
1080 {
1081         ps_service_t *service = object;
1082         g_return_val_if_fail(service != NULL, FALSE);
1083
1084         return service->roaming;
1085 }
1086
1087 gboolean _ps_service_set_roaming(gpointer object, gboolean value)
1088 {
1089         ps_service_t *service = object;
1090         g_return_val_if_fail(service != NULL, FALSE);
1091
1092         service->roaming = value;
1093         ps_dbg_ex_co(_ps_service_ref_co_network(service), "service(%p) roaming(%d)", service, service->roaming);
1094         __ps_service_emit_property_changed_signal(service);
1095
1096         return TRUE;
1097 }
1098
1099 static void _indicator_cb_dns_reply(GObject *src, GAsyncResult *res, gpointer user_data)
1100 {
1101         GList *list, *cur;
1102         GInetAddress *addr;
1103         gchar *str_addr;
1104         GError *error = NULL;
1105
1106         list = g_resolver_lookup_by_name_finish((GResolver *)src, res, &error);
1107         if (!list) {
1108                 dbg("fail to get dns resolving");
1109                 if (error) {
1110                         dbg ("error:%d, %s", error->code, error->message);
1111                         g_error_free (error);
1112                 }
1113                 return;
1114         }
1115
1116         for (cur = list; cur; cur = cur->next) {
1117                 addr = cur->data;
1118                 str_addr = g_inet_address_to_string(addr);
1119                 if (!str_addr)
1120                         continue;
1121                 dbg("addr(%s)", str_addr);
1122
1123                 g_free(str_addr);
1124                 g_object_unref(cur->data);
1125                 break;
1126         }
1127
1128         g_object_unref(src);
1129         g_list_free(list);
1130         return;
1131 }
1132
1133 gboolean _ps_service_set_access_technology(gpointer object,
1134                 enum telephony_network_access_technology value)
1135 {
1136         ps_service_t *service = object;
1137         CoreObject *co_network = NULL;
1138         enum telephony_network_access_technology p_act = 0;
1139         g_return_val_if_fail(service != NULL, FALSE);
1140
1141         co_network = _ps_service_ref_co_network(service);
1142         p_act = service->act;
1143         service->act = value;
1144         ps_dbg_ex_co(co_network, "service(%p) P ACT(%d) Access Technology(%d)", service, p_act, service->act);
1145
1146         if(p_act == NETWORK_ACT_LTE && (service->act >= NETWORK_ACT_GSM && service->act < NETWORK_ACT_LTE) ){
1147                 GResolver *r = NULL;
1148
1149                 ps_dbg_ex_co(co_network, "send the dns pkt for keeping connection");
1150
1151                 r = g_resolver_get_default();
1152                 g_resolver_lookup_by_name_async(r, "www.google.com", NULL, _indicator_cb_dns_reply, NULL);
1153         }
1154
1155         if(service->act > NETWORK_ACT_UNKNOWN && service->act < NETWORK_ACT_NOT_SPECIFIED){
1156                 _ps_update_cellular_state_key(service);
1157                 _ps_service_connect_default_context(service);
1158         }
1159
1160         return TRUE;
1161 }
1162
1163 enum telephony_ps_state _ps_service_check_cellular_state(gpointer object)
1164 {
1165         gboolean state = FALSE;
1166         ps_service_t *service = object;
1167         g_return_val_if_fail(service != NULL, TELEPHONY_PS_NO_SERVICE);
1168
1169         state = _ps_modem_get_flght_mode(service->p_modem);
1170         if(state){
1171                 return TELEPHONY_PS_FLIGHT_MODE;
1172         }
1173
1174         state = _ps_modem_get_power(service->p_modem);
1175         if(!state){
1176                 return TELEPHONY_PS_NO_SERVICE;
1177         }
1178
1179         state = _ps_modem_get_sim_init(service->p_modem);
1180         if(!state){
1181                 return TELEPHONY_PS_NO_SERVICE;
1182         }
1183
1184         if(service->restricted){
1185                 return TELEPHONY_PS_RESTRICTED_SERVICE;
1186         }
1187
1188         if(!service->ps_attached){
1189                 return TELEPHONY_PS_NO_SERVICE;
1190         }
1191
1192         state = _ps_modem_get_data_allowed(service->p_modem);
1193         if(!state){
1194                 return TELEPHONY_PS_3G_OFF;
1195         }
1196
1197         state = _ps_modem_get_data_roaming_allowed(service->p_modem);
1198         if(service->roaming && !state){
1199                 return TELEPHONY_PS_ROAMING_OFF;
1200         }
1201
1202         return TELEPHONY_PS_ON;
1203 }
1204 static gboolean on_service_get_properties (PacketServiceService *obj_service,
1205                 GDBusMethodInvocation *invocation,
1206                 gpointer user_data)
1207 {
1208         GVariant *gv = NULL;
1209         GVariantBuilder property;
1210         ps_dbg_ex_co(_ps_service_ref_co_network(user_data), "get service properties");
1211
1212         gv = _ps_service_get_properties(user_data, &property);
1213         packet_service_service_complete_get_properties(obj_service, invocation, gv);
1214         return TRUE;
1215 }
1216
1217 static gboolean
1218 on_service_get_context (PacketServiceService *obj_service,
1219                 GDBusMethodInvocation *invocation,
1220                 gpointer user_data)
1221 {
1222         GVariantBuilder b_context;
1223         GVariant *contexts;
1224
1225         GHashTableIter iter;
1226         gpointer key, value;
1227         ps_service_t *service = user_data;
1228         CoreObject *co_network = _ps_service_ref_co_network(service);
1229
1230         ps_dbg_ex_co(co_network, "modem get contexts interface");
1231
1232         if (service->contexts == NULL) {
1233                 ps_err_ex_co(co_network, "No context present for service");
1234                 FAIL_RESPONSE(invocation,PS_ERR_INTERNAL);
1235                 return TRUE;
1236         }
1237
1238         g_variant_builder_init(&b_context, G_VARIANT_TYPE("a{sa{ss}}"));
1239         g_hash_table_iter_init(&iter, service->contexts);
1240         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1241                 gchar *path = NULL;
1242                 g_variant_builder_open(&b_context,G_VARIANT_TYPE("{sa{ss}}"));
1243                 path = _ps_service_ref_path(value);
1244
1245                 g_variant_builder_add(&b_context, "s",g_strdup(path));
1246                 if(FALSE == _ps_context_get_properties_handler(value, &b_context)){
1247                         ps_err_ex_co(co_network, "Failed to get property");
1248                         g_variant_builder_close(&b_context);
1249                         FAIL_RESPONSE(invocation,PS_ERR_INTERNAL);
1250                         return TRUE;
1251                 }
1252                 g_variant_builder_close(&b_context);
1253
1254         }
1255
1256         contexts = g_variant_builder_end(&b_context);
1257         packet_service_service_complete_get_contexts(obj_service, invocation,contexts);
1258         return TRUE;
1259 }
1260
1261 static void _ps_service_setup_interface(PacketServiceService *service, ps_service_t *service_data)
1262 {
1263         dbg("Entered");
1264         g_signal_connect (service,
1265                         "handle-get-properties",
1266                         G_CALLBACK (on_service_get_properties),
1267                         service_data);
1268
1269         g_signal_connect (service,
1270                         "handle-get-contexts",
1271                         G_CALLBACK (on_service_get_context),
1272                         service_data);
1273
1274         dbg("Exiting");
1275         return;
1276 }
1277