fix SPN display issue
[platform/core/telephony/tel-plugin-imc.git] / src / imc_ps.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2013 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
23 #include <glib.h>
24
25 #include <tcore.h>
26 #include <server.h>
27 #include <plugin.h>
28 #include <core_object.h>
29 #include <hal.h>
30 #include <queue.h>
31 #include <storage.h>
32 #include <at.h>
33
34 #include <co_ps.h>
35 #include <co_context.h>
36
37 #include "imc_ps.h"
38 #include "imc_common.h"
39
40 typedef struct {
41         TcorePsCallState ps_call_status;
42 } PrivateInfo;
43
44 static void __notify_context_status_changed(CoreObject *co_ps, guint context_id,
45                                                 TcorePsCallState status)
46 {
47         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
48         TcorePsCallStatusInfo data_resp = {0,};
49         tcore_check_return_assert(private_info != NULL);
50
51         private_info->ps_call_status = status;
52         data_resp.context_id = context_id;
53         data_resp.state = status;
54         dbg("Sending PS Call Status Notification - Context ID: [%d] Context State: [%d]",
55                                         data_resp.context_id, data_resp.state);
56
57         /* Send PS CALL Status Notification */
58         (void)tcore_object_send_notification(co_ps,
59                         TCORE_NOTIFICATION_PS_CALL_STATUS,
60                         sizeof(TcorePsCallStatusInfo),
61                         &data_resp);
62
63 }
64
65 static TcoreHookReturn on_hook_imc_nw_registration_status(TcorePlugin *plugin,
66     TcoreNotification command, guint data_len, void *data, void *user_data)
67 {
68         const TelNetworkRegStatusInfo *nw_reg_status = (TelNetworkRegStatusInfo *)data;
69         gboolean state = FALSE;
70
71         tcore_check_return_value(nw_reg_status != NULL,
72         TCORE_HOOK_RETURN_CONTINUE);
73
74
75         dbg("nw_reg_status->ps_status [%d]",nw_reg_status->ps_status);
76         dbg("nw_reg_status->cs_status [%d]",nw_reg_status->cs_status);
77
78         /* Setting if PS is online or not */
79         if(nw_reg_status->ps_status == TEL_NETWORK_REG_STATUS_REGISTERED ||
80                 nw_reg_status->ps_status == TEL_NETWORK_REG_STATUS_ROAMING) {
81                 /* Set PS is online */
82                 state = TRUE;
83         }
84
85         dbg("PS online state [%d]", state);
86
87         /* Set Online state */
88         tcore_ps_set_online((CoreObject *)user_data, state);
89         return TCORE_HOOK_RETURN_CONTINUE;
90 }
91
92 /*
93  * Notification - GPRS event reporting
94  *
95  * Notification -
96  * +CGEV: NW DEACT <PDP_type>, <PDP_addr>, [<cid>]
97  * The network has forced a context deactivation. The <cid> that was used to activate the context is provided if
98  * known to the MT
99  */
100 static gboolean on_notification_imc_ps_cgev(CoreObject *co_ps,
101         const void *data, void *user_data)
102 {
103         GSList *tokens = NULL;
104         GSList *lines = (GSList *)data;
105         const gchar *line = lines->data;
106         gchar *noti_data;
107         guint context_id;
108         TcoreHal *hal;
109
110         dbg("Entry");
111
112         if (line == NULL) {
113                 err("Ignore, No data present in notification received for CGEV");
114                 return TRUE;
115         }
116
117         dbg("Lines->data :%s", line);
118
119         tokens = tcore_at_tok_new(line);
120         if (g_slist_length(tokens) != 3) {
121                 err("Ignore, sufficient data not present for deactivation");
122                 goto out;
123
124         }
125         noti_data = g_slist_nth_data(tokens, 0);
126
127         /* Only care about NW context deactivation */
128         if (g_str_has_prefix(noti_data, "NW DEACT") == FALSE) {
129                 err("Ignore, only care about nw deactivation");
130                 goto out;
131         }
132
133         noti_data = g_slist_nth_data(tokens, 1);
134         dbg("PDP Address: %s", noti_data);
135
136         noti_data = g_slist_nth_data(tokens, 2);
137         /*TODO: Need to handle context id with multiple PDP*/
138         if (noti_data != NULL)
139                 context_id = (guint)atoi(noti_data);
140         else{
141                 err("No Context ID!");
142                 goto out;
143         }
144
145         dbg("Context %d deactivated", context_id);
146
147         __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED);
148
149         hal = tcore_object_get_hal(co_ps);
150         if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id,
151                                         FALSE) != TEL_RETURN_SUCCESS)
152                 err("Failed to disable network interface");
153 out:
154         tcore_at_tok_free(tokens);
155         return TRUE;
156 }
157
158 static void __imc_ps_setup_pdp(CoreObject *co_ps, gint result, const gchar *netif_name,
159         void *user_data)
160 {
161         CoreObject *ps_context = user_data;
162         guint context_id;
163
164         tcore_check_return_assert(ps_context != NULL);
165
166         dbg("Enter");
167
168         if (result < 0) {
169                 err("Result [%d],Hence Deactivating context ", result);
170                 /* Deactivate PDP context */
171                 (void)tcore_object_dispatch_request(co_ps, TRUE,
172                                 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
173                                 NULL, 0,
174                                 NULL, NULL);
175
176                 return;
177         }
178
179         dbg("devname = [%s]", netif_name);
180
181         tcore_context_set_ipv4_devname(ps_context, netif_name);
182
183         (void)tcore_context_get_id(ps_context, &context_id);
184         dbg("Context ID : %d", context_id);
185
186         __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_CONNECTED);
187
188         dbg("Exit");
189 }
190
191 static void __on_response_imc_ps_send_get_dns_cmd(TcorePending *p, guint data_len, const void *data, void *user_data)
192 {
193         const TcoreAtResponse *at_resp = data;
194         CoreObject *ps_context = user_data;
195         CoreObject *co_ps = tcore_pending_ref_core_object(p);
196         guint context_id;
197         GSList *tokens = NULL;
198         GSList *lines;
199         const char *line = NULL;
200         char *dns_prim = NULL;
201         char *dns_sec = NULL;
202         char *token_dns = NULL;
203         gint no_pdp_active = 0;
204         TcoreHal *hal = tcore_object_get_hal(co_ps);
205
206         dbg("Entered");
207
208         tcore_check_return_assert(at_resp != NULL);
209         tcore_check_return_assert(ps_context != NULL);
210
211
212         (void)tcore_context_get_id(ps_context, &context_id);
213         dbg("Context ID : %d", context_id);
214
215         if (at_resp && at_resp->success) {
216                 dbg("Response OK");
217                 if (at_resp->lines) {
218                         dbg("DNS data present in the Response");
219                         lines = (GSList *) at_resp->lines;
220                         no_pdp_active = g_slist_length(lines);
221                         dbg("Total Number of Active PS Context: [%d]", no_pdp_active);
222                         if (0 == no_pdp_active) {
223                                 goto fail;
224                         }
225
226                         while (lines) {
227                                 line = (const char *) lines->data;
228                                 dbg("Received Data: [%s]", line);
229                                 tokens = tcore_at_tok_new(line);
230
231                                 /* Check if Context ID is matching */
232                                 if (context_id == (guint)(atoi(g_slist_nth_data(tokens, 0)))) {
233                                         dbg("Found the DNS details for the Current Context - Context ID: [%d]", context_id);
234                                         break;
235                                 }
236
237                                 tcore_at_tok_free(tokens);
238                                 tokens = NULL;
239
240                                 /* Move to next line */
241                                 lines = lines->next;
242                         }
243
244                         /* Read primary DNS */
245                         {
246                                 token_dns = g_slist_nth_data(tokens, 1);
247                                 dns_prim = tcore_at_tok_extract(token_dns);
248                                 dbg("Primary DNS: [%s]", dns_prim);
249                         }
250
251                         /* Read Secondary DNS */
252                         {
253                                 token_dns = g_slist_nth_data(tokens, 2);
254                                 dns_sec = tcore_at_tok_extract(token_dns);
255                                 dbg("Secondary DNS: [%s]", dns_sec);
256                         }
257
258                         if ((g_strcmp0("0.0.0.0", dns_prim) == 0)
259                                         && (g_strcmp0("0.0.0.0", dns_sec) == 0)) {
260                                 dbg("Invalid DNS");
261
262                                 tcore_free(dns_prim);
263                                 tcore_free(dns_sec);
264
265                                 tcore_at_tok_free(tokens);
266                                 tokens = NULL;
267
268                                 goto fail;
269                         }
270
271                         /* Set DNS Address */
272                         tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
273                         tcore_free(dns_prim);
274                         tcore_free(dns_sec);
275
276                         tcore_at_tok_free(tokens);
277                         tokens = NULL;
278                         goto success;
279                 } else {
280                         dbg("No data present in the Response");
281                 }
282         }
283         dbg("Response NOK");
284
285 fail:
286         dbg("Adding default DNS");
287         tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
288
289 success:
290         /* Mount network interface */
291         if (tcore_hal_setup_netif(hal, co_ps, __imc_ps_setup_pdp, ps_context, context_id, TRUE)
292                         != TEL_RETURN_SUCCESS) {
293                 err("Setup network interface failed");
294                 return;
295         }
296 }
297
298 static void __imc_ps_send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
299 {
300         TelReturn ret = TEL_RETURN_FAILURE;
301         guint context_id;
302         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
303
304         dbg("Entered");
305
306         tcore_check_return_assert(private_info != NULL);
307
308         (void)tcore_context_get_id(ps_context, &context_id);
309         dbg("Context ID : %d", context_id);
310
311         /* Send Request to modem */
312         ret = tcore_at_prepare_and_send_request(co_ps,
313                 "AT+XDNS?", "+XDNS",
314                 TCORE_AT_COMMAND_TYPE_MULTILINE,
315                 TCORE_PENDING_PRIORITY_DEFAULT,
316                 NULL,
317                 __on_response_imc_ps_send_get_dns_cmd,
318                 ps_context,
319                 on_send_imc_request, NULL,
320                 0, NULL, NULL);
321
322         if (ret != TEL_RETURN_SUCCESS){
323                 TcorePsCallState curr_call_status;
324                 err("Failed to prepare and send AT request");
325                 curr_call_status = private_info->ps_call_status;
326                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
327         }
328 }
329
330 static void __on_response_imc_ps_get_pdp_address(TcorePending *p, guint data_len,
331                                         const void *data, void *user_data)
332 {
333         const TcoreAtResponse *at_resp = data;
334         CoreObject *co_ps = tcore_pending_ref_core_object(p);
335         CoreObject *ps_context = user_data;
336         GSList *tokens = NULL;
337         const char *line;
338         char *pdp_address;
339         char *real_pdp_address;
340
341         dbg("Entered");
342
343         tcore_check_return_assert(at_resp != NULL);
344         tcore_check_return_assert(ps_context != NULL);
345
346         if (at_resp->success != TRUE) {
347                 err("Response NOt OK");
348                 goto error;
349         }
350
351         dbg("Response OK");
352
353         if (at_resp->lines == NULL) {
354                 err("Invalid response line");
355                 goto error;
356         }
357
358         line = (const char *)at_resp->lines->data;
359         tokens = tcore_at_tok_new(line);
360         if (g_slist_length(tokens) < 2) {
361                 err("Invalid message");
362                 goto error;
363         }
364
365         dbg("Line: %s", line);
366
367         /* Skip CID & read directly IP address */
368         pdp_address = g_slist_nth_data(tokens, 1);
369         real_pdp_address = tcore_at_tok_extract(pdp_address);
370
371         tcore_context_set_ipv4_addr(ps_context, real_pdp_address);
372
373         dbg("PDP address: %s", real_pdp_address);
374
375         tcore_free(real_pdp_address);
376
377         /* Get DNS Address */
378         dbg("Getting DNS Address");
379         __imc_ps_send_get_dns_cmd(co_ps, ps_context);
380         goto exit;
381
382 error:
383         err("Failed to get PDP address deactivating context...");
384         /* Deactivate PDP context */
385         (void)tcore_object_dispatch_request(co_ps, TRUE,
386                         TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
387                         NULL, 0,
388                         NULL, NULL);
389 exit:
390         tcore_at_tok_free(tokens);
391         dbg("Exit");
392 }
393
394 static void __imc_ps_get_pdp_address(CoreObject *co_ps, CoreObject *ps_context)
395 {
396         TelReturn ret;
397         gchar *at_cmd = NULL;
398         guint context_id;
399
400         dbg("Entered");
401
402         (void)tcore_context_get_id(ps_context, &context_id);
403         dbg("Context ID : %d", context_id);
404
405         /* AT-Command */
406         at_cmd = g_strdup_printf("AT+CGPADDR=%d", context_id);
407         dbg(" at command : %s", at_cmd);
408
409         /* Send Request to modem */
410         ret = tcore_at_prepare_and_send_request(co_ps,
411                 at_cmd, NULL,
412                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
413                 TCORE_PENDING_PRIORITY_DEFAULT,
414                 NULL,
415                 __on_response_imc_ps_get_pdp_address,
416                 ps_context,
417                 on_send_imc_request, NULL,
418                 0, NULL, NULL);
419
420         if (ret != TEL_RETURN_SUCCESS){
421                 err("Failed to prepare and send AT request");
422                 /* Deactivate PDP context */
423                 (void)tcore_object_dispatch_request(co_ps, TRUE,
424                                 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
425                                 &ps_context, sizeof(CoreObject *),
426                                 NULL, NULL);
427         }
428         tcore_free(at_cmd);
429 }
430
431 static void __on_response_imc_ps_send_xdns_enable_cmd(TcorePending *p,
432                                 guint data_len, const void *data, void *user_data)
433 {
434         const TcoreAtResponse *at_resp = data;
435         CoreObject *co_ps = tcore_pending_ref_core_object(p);
436         CoreObject *ps_context = (CoreObject *) user_data;
437         guint context_id;
438         TcorePsCallState status = TCORE_PS_CALL_STATE_NOT_CONNECTED;
439
440         tcore_check_return_assert(at_resp != NULL);
441         tcore_check_return_assert(ps_context != NULL);
442
443         dbg("Entered");
444
445         (void)tcore_context_get_id(ps_context, &context_id);
446         dbg("Context ID : %d", context_id);
447
448         if (at_resp->success) {
449                 dbg("Response OK, Dynamic DNS is enabled successfully");
450                 status = TCORE_PS_CALL_STATE_CTX_DEFINED;
451         } else {
452                 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
453                 tcore_check_return_assert(private_info != NULL);
454
455                 status = private_info->ps_call_status;
456                 err("ERROR [%s]", at_resp->final_response);
457         }
458         /* Send PS CALL Status Notification */
459         __notify_context_status_changed(co_ps, context_id, status);
460 }
461
462 static TelReturn __imc_ps_send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
463 {
464         guint context_id;
465         gchar *at_cmd = NULL;
466         TelReturn ret;
467         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
468
469         tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
470
471         dbg("Entered");
472
473         (void)tcore_context_get_id(ps_context, &context_id);
474         dbg("Context ID : %d", context_id);
475
476         /* AT-Command */
477         at_cmd = g_strdup_printf("AT+XDNS=%d,1", context_id);
478         dbg("AT Command : %s", at_cmd);
479
480         /* Send Request to modem */
481         ret = tcore_at_prepare_and_send_request(co_ps,
482                 at_cmd, NULL,
483                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
484                 TCORE_PENDING_PRIORITY_DEFAULT,
485                 NULL,
486                 __on_response_imc_ps_send_xdns_enable_cmd,
487                 ps_context,
488                 on_send_imc_request, NULL,
489                 0, NULL, NULL);
490
491         if (ret != TEL_RETURN_SUCCESS){
492                 TcorePsCallState curr_call_status;
493
494                 err("Failed to prepare and send AT request");
495                 curr_call_status = private_info->ps_call_status;
496                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
497         }
498         return ret;
499 }
500
501 static void on_response_imc_ps_activate_context(TcorePending *p, guint data_len,
502                                                         const void *data,
503                                                         void *user_data)
504 {
505         const TcoreAtResponse *at_resp = data;
506         CoreObject *co_ps = tcore_pending_ref_core_object(p);
507         CoreObject *ps_context = user_data;
508         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
509
510         dbg("Entered");
511
512         tcore_check_return_assert(at_resp != NULL);
513         tcore_check_return_assert(ps_context != NULL);
514         tcore_check_return_assert(private_info != NULL);
515
516         if (at_resp->success) {
517                 dbg("Response OK, Get IP address of data session");
518                 __imc_ps_get_pdp_address(co_ps, ps_context);
519         } else {
520                 guint context_id;
521                 TcorePsCallState curr_call_status;
522                 (void)tcore_context_get_id(ps_context, &context_id);
523                 err("Response NOT OK,Sending call disconnect notification");
524                 curr_call_status = private_info->ps_call_status;
525                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
526         }
527 }
528
529 static void on_response_imc_ps_deactivate_context(TcorePending *p, guint data_len,
530                                                         const void *data,
531                                                         void *user_data)
532 {
533         const TcoreAtResponse *at_resp = data;
534         CoreObject *co_ps = tcore_pending_ref_core_object(p);
535         CoreObject *ps_context = user_data;
536         TcoreHal *hal = tcore_object_get_hal(co_ps);
537         guint context_id;
538
539         dbg("Entered");
540
541         tcore_check_return_assert(at_resp != NULL);
542         tcore_check_return_assert(ps_context != NULL);
543
544         (void)tcore_context_get_id(ps_context, &context_id);
545         dbg("Context ID : %d", context_id);
546
547         /*
548          * AT+CGACT = 0 is returning NO CARRIER or an error. Just test if the
549          * response contains NO CARRIER else decode CME error.
550          */
551 #if 0
552         if (at_resp->success) {
553                 const gchar *line;
554
555                 line = (const gchar *)at_resp->lines->data;
556                 if (g_strcmp0(line, "NO CARRIER") != 0) {
557                         err("%s", line);
558                         err("Context %d has not been deactivated", context_id);
559
560                         goto out;
561                 }
562         }
563
564 #endif
565         __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED);
566
567         if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id, FALSE) != TEL_RETURN_SUCCESS)
568                 err("Failed to disable network interface");
569 }
570
571 static void on_response_imc_ps_define_context(TcorePending *p,
572                                 guint data_len, const void *data, void *user_data)
573 {
574         const TcoreAtResponse *at_resp = data;
575         CoreObject *ps_context = (CoreObject *) user_data;
576         CoreObject *co_ps = tcore_pending_ref_core_object(p);
577         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
578
579         dbg("Entred");
580
581         tcore_check_return_assert(at_resp != NULL);
582         tcore_check_return_assert(ps_context != NULL);
583         tcore_check_return_assert(private_info != NULL);
584
585         if (at_resp->success) {
586                 dbg("Response OK,Sending DNS enable command");
587                 __imc_ps_send_xdns_enable_cmd(co_ps, ps_context);
588         } else {
589                 guint context_id;
590                 TcorePsCallState curr_call_status;
591
592                 err("ERROR[%s]", at_resp->final_response);
593                 (void)tcore_context_get_id(ps_context, &context_id);
594                 curr_call_status = private_info->ps_call_status;
595                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
596         }
597 }
598
599 /*
600  * Operation - PDP Context Activate
601  *
602  * Request -
603  * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
604  *
605  * where,
606  * <state>
607  * indicates the state of PDP context activation
608  *
609  * 1 activated
610  *
611  * <cid>
612  * It is a numeric parameter which specifies a particular PDP context definition
613  *
614  * Response -
615  * Success: (No Result)
616  *      OK
617  * Failure:
618  *      +CME ERROR: <error>
619  */
620
621 static TelReturn imc_ps_activate_context(CoreObject *co_ps, CoreObject *ps_context,
622                                 TcoreObjectResponseCallback cb, void *cb_data)
623 {
624         TelReturn ret = TEL_RETURN_FAILURE;
625         gchar *at_cmd = NULL;
626         guint context_id;
627         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
628
629         tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
630
631         dbg("Entered");
632
633         (void)tcore_context_get_id(ps_context, &context_id);
634         dbg("Context ID : %d", context_id);
635
636         at_cmd = g_strdup_printf("AT+CGACT=1,%d", context_id);
637         dbg(" at command : %s", at_cmd);
638
639         /* Send Request to modem */
640         ret = tcore_at_prepare_and_send_request(co_ps,
641                 at_cmd, NULL,
642                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
643                 TCORE_PENDING_PRIORITY_DEFAULT,
644                 NULL,
645                 on_response_imc_ps_activate_context,
646                 ps_context,
647                 on_send_imc_request, NULL,
648                 0, NULL, NULL);
649
650         if (ret != TEL_RETURN_SUCCESS){
651                 TcorePsCallState curr_call_status;
652                 curr_call_status = private_info->ps_call_status;
653                 err("AT request failed. Send notification for call status [%d]", curr_call_status);
654                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
655         }
656         tcore_free(at_cmd);
657         return ret;
658 }
659
660 /*
661  * Operation - PDP Context Deactivate
662  *
663  * Request -
664  * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
665  *
666  * where,
667  * <state>
668  * indicates the state of PDP context activation
669  *
670  * 0 deactivated
671  *
672  * <cid>
673  * It is a numeric parameter which specifies a particular PDP context definition
674  *
675  * Response -
676  * Success: (No Result)
677  *      OK
678  * Failure:
679  *      +CME ERROR: <error>
680  */
681 static TelReturn imc_ps_deactivate_context(CoreObject *co_ps, CoreObject *ps_context,
682                                 TcoreObjectResponseCallback cb, void *cb_data)
683 {
684         TelReturn ret = TEL_RETURN_FAILURE;
685         gchar *at_cmd = NULL;
686         guint context_id;
687         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
688
689         tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
690
691         dbg("Entered");
692
693         (void)tcore_context_get_id(ps_context, &context_id);
694         dbg("Context ID : %d", context_id);
695
696         at_cmd = g_strdup_printf("AT+CGACT=0,%d", context_id);
697         dbg(" at command : %s", at_cmd);
698
699         /* Send Request to modem */
700         ret = tcore_at_prepare_and_send_request(co_ps,
701                 at_cmd, NULL,
702                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
703                 TCORE_PENDING_PRIORITY_DEFAULT,
704                 NULL,
705                 on_response_imc_ps_deactivate_context,
706                 ps_context,
707                 on_send_imc_request, NULL,
708                 0, NULL, NULL);
709
710         if (ret != TEL_RETURN_SUCCESS){
711                 TcorePsCallState curr_call_status;
712                 curr_call_status = private_info->ps_call_status;
713                 err("AT request failed. Send notification for call status [%d]", curr_call_status);
714                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
715         }
716         tcore_free(at_cmd);
717         return ret;
718 }
719
720 /*
721  * Operation - Define PDP Context
722  *
723  * Request -
724  * AT-Command: AT+CGDCONT= [<cid> [, <PDP_type> [, <APN> [, <PDP_addr> [,
725  * <d_comp> [, <h_comp> [, <pd1> [... [, pdN]]]]]]]]]
726  * where,
727  * <cid>
728  * It is a numeric parameter, which specifies a particular PDP context definition
729  *
730  * <PDP_type>
731  * "IP" Internet Protocol (IETF STD 5)
732  * "IPV6" Internet Protocol, version 6 (IETF RFC 2460)
733  * "IPV4V6" Virtual <PDP_type>introduced to handle dual IP stack UE capability (see 3GPP
734  *  TS 24.301[83])
735  *
736  * <APN>
737  * Access Point Name
738  *
739  * <PDP_address>
740  * It is the string parameter that identifies the MT in the address space applicable to the PDP
741  * The allocated address may be read using the command +CGPADDR command
742  *
743  * <d_comp>
744  * A numeric parameter that controls PDP data compression
745  * 0 off
746  * 1 on
747  * 2 V.42 bis
748  *
749  * <h_comp>
750  * A numeric parameter that controls PDP header compression
751  * 0 off
752  * 1 on
753  * 2 RFC1144
754  * 3 RFC2507
755  * 4 RFC3095
756  *
757  * <pd1>...<pdN>
758  * zero to N string parameters whose meanings are specific to the <PDP_type>
759  *
760  * Response -
761  * Success: (No Result)
762  *      OK
763  * Failure:
764  *      +CME ERROR: <error>
765  */
766 static TelReturn imc_ps_define_context(CoreObject *co_ps, CoreObject *ps_context,
767                                 TcoreObjectResponseCallback cb, void *cb_data)
768 {
769         TelReturn ret = TEL_RETURN_FAILURE;
770         gchar *at_cmd = NULL;
771         guint context_id = 0;
772         gchar *apn = NULL;
773         gchar *pdp_type_str = NULL;
774         TcoreContextType pdp_type;
775         TcoreContextDComp d_comp;
776         TcoreContextHComp h_comp;
777         TcorePsCallState curr_call_status;
778
779         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
780
781         tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
782
783         dbg("Entred");
784
785         (void)tcore_context_get_id(ps_context, &context_id);
786         (void)tcore_context_get_type(ps_context, &pdp_type);
787
788         switch (pdp_type) {
789         case TCORE_CONTEXT_TYPE_X25:
790                 dbg("CONTEXT_TYPE_X25");
791                 pdp_type_str = g_strdup("X.25");
792         break;
793
794         case TCORE_CONTEXT_TYPE_IP:
795                 dbg("CONTEXT_TYPE_IP");
796                 pdp_type_str = g_strdup("IP");
797         break;
798
799         case TCORE_CONTEXT_TYPE_PPP:
800                 dbg("CONTEXT_TYPE_PPP");
801                 pdp_type_str = g_strdup("PPP");
802         break;
803
804         case TCORE_CONTEXT_TYPE_IPV6:
805                 dbg("CONTEXT_TYPE_IPV6");
806                 pdp_type_str = g_strdup("IPV6");
807                 break;
808
809         default:
810                 /*PDP Type not supported*/
811                 dbg("Unsupported PDP type: %d", pdp_type);
812                 goto error;
813         }
814
815         (void)tcore_context_get_data_compression(ps_context, &d_comp);
816         (void)tcore_context_get_header_compression(ps_context, &h_comp);
817         (void)tcore_context_get_apn(ps_context, &apn);
818
819         dbg("Define context for CID: %d", context_id);
820
821         /* AT-Command */
822         at_cmd = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", context_id, pdp_type_str, apn, d_comp, h_comp);
823         dbg("AT Command : %s", at_cmd);
824
825         /* Send Request to modem */
826         ret = tcore_at_prepare_and_send_request(co_ps,
827                 at_cmd, NULL,
828                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
829                 TCORE_PENDING_PRIORITY_DEFAULT,
830                 NULL,
831                 on_response_imc_ps_define_context,
832                 ps_context,
833                 on_send_imc_request, NULL,
834                 0, NULL, NULL);
835
836         tcore_free(pdp_type_str);
837         tcore_free(at_cmd);
838         tcore_free(apn);
839
840         if (ret == TEL_RETURN_SUCCESS)
841                 goto out;
842
843 error:
844         err("Failed to prepare and send AT request");
845
846         curr_call_status = private_info->ps_call_status;
847         __notify_context_status_changed(co_ps, context_id, curr_call_status);
848
849 out:
850         return ret;
851 }
852
853 /* PS Operations */
854 static TcorePsOps imc_ps_ops = {
855         .define_context = imc_ps_define_context,
856         .activate_context = imc_ps_activate_context,
857         .deactivate_context = imc_ps_deactivate_context
858 };
859
860
861 gboolean imc_ps_init(TcorePlugin *p, CoreObject *co)
862 {
863         PrivateInfo *private_info;
864
865         dbg("Entry");
866
867         /* Set PrivateInfo */
868         private_info = tcore_malloc0(sizeof(PrivateInfo));
869         tcore_object_link_user_data(co, private_info);
870
871         /* Set operations */
872         tcore_ps_set_ops(co, &imc_ps_ops);
873
874         /* Add Callbacks */
875         tcore_object_add_callback(co, "+CGEV", on_notification_imc_ps_cgev, NULL);
876
877         tcore_plugin_add_notification_hook(p,
878         TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS,
879         on_hook_imc_nw_registration_status, co);
880
881         dbg("Exit");
882         return TRUE;
883 }
884
885 void imc_ps_exit(TcorePlugin *p, CoreObject *co)
886 {
887         PrivateInfo *private_info;
888
889         private_info = tcore_object_ref_user_data(co);
890         tcore_check_return_assert(private_info != NULL);
891
892         tcore_free(private_info);
893
894         dbg("Exit");
895 }