Set sms parameter fix
[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                 NULL,
316                 __on_response_imc_ps_send_get_dns_cmd,
317                 ps_context,
318                 on_send_imc_request, NULL);
319         if (ret != TEL_RETURN_SUCCESS){
320                 TcorePsCallState curr_call_status;
321                 err("Failed to prepare and send AT request");
322                 curr_call_status = private_info->ps_call_status;
323                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
324         }
325 }
326
327 static void __on_response_imc_ps_get_pdp_address(TcorePending *p, guint data_len,
328                                         const void *data, void *user_data)
329 {
330         const TcoreAtResponse *at_resp = data;
331         CoreObject *co_ps = tcore_pending_ref_core_object(p);
332         CoreObject *ps_context = user_data;
333         GSList *tokens = NULL;
334         const char *line;
335         char *pdp_address;
336         char *real_pdp_address;
337
338         dbg("Entered");
339
340         tcore_check_return_assert(at_resp != NULL);
341         tcore_check_return_assert(ps_context != NULL);
342
343         if (at_resp->success != TRUE) {
344                 err("Response NOt OK");
345                 goto error;
346         }
347
348         dbg("Response OK");
349
350         if (at_resp->lines == NULL) {
351                 err("Invalid response line");
352                 goto error;
353         }
354
355         line = (const char *)at_resp->lines->data;
356         tokens = tcore_at_tok_new(line);
357         if (g_slist_length(tokens) < 2) {
358                 err("Invalid message");
359                 goto error;
360         }
361
362         dbg("Line: %s", line);
363
364         /* Skip CID & read directly IP address */
365         pdp_address = g_slist_nth_data(tokens, 1);
366         real_pdp_address = tcore_at_tok_extract(pdp_address);
367
368         tcore_context_set_ipv4_addr(ps_context, real_pdp_address);
369
370         dbg("PDP address: %s", real_pdp_address);
371
372         tcore_free(real_pdp_address);
373
374         /* Get DNS Address */
375         dbg("Getting DNS Address");
376         __imc_ps_send_get_dns_cmd(co_ps, ps_context);
377         goto exit;
378
379 error:
380         err("Failed to get PDP address deactivating context...");
381         /* Deactivate PDP context */
382         (void)tcore_object_dispatch_request(co_ps, TRUE,
383                         TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
384                         NULL, 0,
385                         NULL, NULL);
386 exit:
387         tcore_at_tok_free(tokens);
388         dbg("Exit");
389 }
390
391 static void __imc_ps_get_pdp_address(CoreObject *co_ps, CoreObject *ps_context)
392 {
393         TelReturn ret;
394         gchar *at_cmd = NULL;
395         guint context_id;
396
397         dbg("Entered");
398
399         (void)tcore_context_get_id(ps_context, &context_id);
400         dbg("Context ID : %d", context_id);
401
402         /* AT-Command */
403         at_cmd = g_strdup_printf("AT+CGPADDR=%d", context_id);
404         dbg(" at command : %s", at_cmd);
405
406         /* Send Request to modem */
407         ret = tcore_at_prepare_and_send_request(co_ps,
408                 at_cmd, NULL,
409                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
410                 NULL,
411                 __on_response_imc_ps_get_pdp_address,
412                 ps_context,
413                 on_send_imc_request, NULL);
414         if (ret != TEL_RETURN_SUCCESS){
415                 err("Failed to prepare and send AT request");
416                 /* Deactivate PDP context */
417                 (void)tcore_object_dispatch_request(co_ps, TRUE,
418                                 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
419                                 &ps_context, sizeof(CoreObject *),
420                                 NULL, NULL);
421         }
422         tcore_free(at_cmd);
423 }
424
425 static void __on_response_imc_ps_send_xdns_enable_cmd(TcorePending *p,
426                                 guint data_len, const void *data, void *user_data)
427 {
428         const TcoreAtResponse *at_resp = data;
429         CoreObject *co_ps = tcore_pending_ref_core_object(p);
430         CoreObject *ps_context = (CoreObject *) user_data;
431         guint context_id;
432         TcorePsCallState status = TCORE_PS_CALL_STATE_NOT_CONNECTED;
433
434         tcore_check_return_assert(at_resp != NULL);
435         tcore_check_return_assert(ps_context != NULL);
436
437         dbg("Entered");
438
439         (void)tcore_context_get_id(ps_context, &context_id);
440         dbg("Context ID : %d", context_id);
441
442         if (at_resp->success) {
443                 dbg("Response OK, Dynamic DNS is enabled successfully");
444                 status = TCORE_PS_CALL_STATE_CTX_DEFINED;
445         } else {
446                 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
447                 tcore_check_return_assert(private_info != NULL);
448
449                 status = private_info->ps_call_status;
450                 err("ERROR [%s]", at_resp->final_response);
451         }
452         /* Send PS CALL Status Notification */
453         __notify_context_status_changed(co_ps, context_id, status);
454 }
455
456 static TelReturn __imc_ps_send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
457 {
458         guint context_id;
459         gchar *at_cmd = NULL;
460         TelReturn ret;
461         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
462
463         tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
464
465         dbg("Entered");
466
467         (void)tcore_context_get_id(ps_context, &context_id);
468         dbg("Context ID : %d", context_id);
469
470         /* AT-Command */
471         at_cmd = g_strdup_printf("AT+XDNS=%d,1", context_id);
472         dbg("AT Command : %s", at_cmd);
473
474         /* Send Request to modem */
475         ret = tcore_at_prepare_and_send_request(co_ps,
476                 at_cmd, NULL,
477                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
478                 NULL,
479                 __on_response_imc_ps_send_xdns_enable_cmd,
480                 ps_context,
481                 on_send_imc_request, NULL);
482         if (ret != TEL_RETURN_SUCCESS){
483                 TcorePsCallState curr_call_status;
484
485                 err("Failed to prepare and send AT request");
486                 curr_call_status = private_info->ps_call_status;
487                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
488         }
489         return ret;
490 }
491
492 static void on_response_imc_ps_activate_context(TcorePending *p, guint data_len,
493                                                         const void *data,
494                                                         void *user_data)
495 {
496         const TcoreAtResponse *at_resp = data;
497         CoreObject *co_ps = tcore_pending_ref_core_object(p);
498         CoreObject *ps_context = user_data;
499         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
500
501         dbg("Entered");
502
503         tcore_check_return_assert(at_resp != NULL);
504         tcore_check_return_assert(ps_context != NULL);
505         tcore_check_return_assert(private_info != NULL);
506
507         if (at_resp->success) {
508                 dbg("Response OK, Get IP address of data session");
509                 __imc_ps_get_pdp_address(co_ps, ps_context);
510         } else {
511                 guint context_id;
512                 TcorePsCallState curr_call_status;
513                 (void)tcore_context_get_id(ps_context, &context_id);
514                 err("Response NOT OK,Sending call disconnect notification");
515                 curr_call_status = private_info->ps_call_status;
516                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
517         }
518 }
519
520 static void on_response_imc_ps_deactivate_context(TcorePending *p, guint data_len,
521                                                         const void *data,
522                                                         void *user_data)
523 {
524         const TcoreAtResponse *at_resp = data;
525         CoreObject *co_ps = tcore_pending_ref_core_object(p);
526         CoreObject *ps_context = user_data;
527         TcoreHal *hal = tcore_object_get_hal(co_ps);
528         guint context_id;
529
530         dbg("Entered");
531
532         tcore_check_return_assert(at_resp != NULL);
533         tcore_check_return_assert(ps_context != NULL);
534
535         (void)tcore_context_get_id(ps_context, &context_id);
536         dbg("Context ID : %d", context_id);
537
538         /*
539          * AT+CGACT = 0 is returning NO CARRIER or an error. Just test if the
540          * response contains NO CARRIER else decode CME error.
541          */
542 #if 0
543         if (at_resp->success) {
544                 const gchar *line;
545
546                 line = (const gchar *)at_resp->lines->data;
547                 if (g_strcmp0(line, "NO CARRIER") != 0) {
548                         err("%s", line);
549                         err("Context %d has not been deactivated", context_id);
550
551                         goto out;
552                 }
553         }
554
555 #endif
556         __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED);
557
558         if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id, FALSE) != TEL_RETURN_SUCCESS)
559                 err("Failed to disable network interface");
560 }
561
562 static void on_response_imc_ps_define_context(TcorePending *p,
563                                 guint data_len, const void *data, void *user_data)
564 {
565         const TcoreAtResponse *at_resp = data;
566         CoreObject *ps_context = (CoreObject *) user_data;
567         CoreObject *co_ps = tcore_pending_ref_core_object(p);
568         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
569
570         dbg("Entred");
571
572         tcore_check_return_assert(at_resp != NULL);
573         tcore_check_return_assert(ps_context != NULL);
574         tcore_check_return_assert(private_info != NULL);
575
576         if (at_resp->success) {
577                 dbg("Response OK,Sending DNS enable command");
578                 __imc_ps_send_xdns_enable_cmd(co_ps, ps_context);
579         } else {
580                 guint context_id;
581                 TcorePsCallState curr_call_status;
582
583                 err("ERROR[%s]", at_resp->final_response);
584                 (void)tcore_context_get_id(ps_context, &context_id);
585                 curr_call_status = private_info->ps_call_status;
586                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
587         }
588 }
589
590 /*
591  * Operation - PDP Context Activate
592  *
593  * Request -
594  * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
595  *
596  * where,
597  * <state>
598  * indicates the state of PDP context activation
599  *
600  * 1 activated
601  *
602  * <cid>
603  * It is a numeric parameter which specifies a particular PDP context definition
604  *
605  * Response -
606  * Success: (No Result)
607  *      OK
608  * Failure:
609  *      +CME ERROR: <error>
610  */
611
612 static TelReturn imc_ps_activate_context(CoreObject *co_ps, CoreObject *ps_context,
613                                 TcoreObjectResponseCallback cb, void *cb_data)
614 {
615         TelReturn ret = TEL_RETURN_FAILURE;
616         gchar *at_cmd = NULL;
617         guint context_id;
618         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
619
620         tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
621
622         dbg("Entered");
623
624         (void)tcore_context_get_id(ps_context, &context_id);
625         dbg("Context ID : %d", context_id);
626
627         at_cmd = g_strdup_printf("AT+CGACT=1,%d", context_id);
628         dbg(" at command : %s", at_cmd);
629
630         /* Send Request to modem */
631         ret = tcore_at_prepare_and_send_request(co_ps,
632                 at_cmd, NULL,
633                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
634                 NULL,
635                 on_response_imc_ps_activate_context,
636                 ps_context,
637                 on_send_imc_request, NULL);
638         if (ret != TEL_RETURN_SUCCESS){
639                 TcorePsCallState curr_call_status;
640                 curr_call_status = private_info->ps_call_status;
641                 err("AT request failed. Send notification for call status [%d]", curr_call_status);
642                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
643         }
644         tcore_free(at_cmd);
645         return ret;
646 }
647
648 /*
649  * Operation - PDP Context Deactivate
650  *
651  * Request -
652  * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
653  *
654  * where,
655  * <state>
656  * indicates the state of PDP context activation
657  *
658  * 0 deactivated
659  *
660  * <cid>
661  * It is a numeric parameter which specifies a particular PDP context definition
662  *
663  * Response -
664  * Success: (No Result)
665  *      OK
666  * Failure:
667  *      +CME ERROR: <error>
668  */
669 static TelReturn imc_ps_deactivate_context(CoreObject *co_ps, CoreObject *ps_context,
670                                 TcoreObjectResponseCallback cb, void *cb_data)
671 {
672         TelReturn ret = TEL_RETURN_FAILURE;
673         gchar *at_cmd = NULL;
674         guint context_id;
675         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
676
677         tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
678
679         dbg("Entered");
680
681         (void)tcore_context_get_id(ps_context, &context_id);
682         dbg("Context ID : %d", context_id);
683
684         at_cmd = g_strdup_printf("AT+CGACT=0,%d", context_id);
685         dbg(" at command : %s", at_cmd);
686
687         /* Send Request to modem */
688         ret = tcore_at_prepare_and_send_request(co_ps,
689                 at_cmd, NULL,
690                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
691                 NULL,
692                 on_response_imc_ps_deactivate_context,
693                 ps_context,
694                 on_send_imc_request, NULL);
695         if (ret != TEL_RETURN_SUCCESS){
696                 TcorePsCallState curr_call_status;
697                 curr_call_status = private_info->ps_call_status;
698                 err("AT request failed. Send notification for call status [%d]", curr_call_status);
699                 __notify_context_status_changed(co_ps, context_id, curr_call_status);
700         }
701         tcore_free(at_cmd);
702         return ret;
703 }
704
705 /*
706  * Operation - Define PDP Context
707  *
708  * Request -
709  * AT-Command: AT+CGDCONT= [<cid> [, <PDP_type> [, <APN> [, <PDP_addr> [,
710  * <d_comp> [, <h_comp> [, <pd1> [... [, pdN]]]]]]]]]
711  * where,
712  * <cid>
713  * It is a numeric parameter, which specifies a particular PDP context definition
714  *
715  * <PDP_type>
716  * "IP" Internet Protocol (IETF STD 5)
717  * "IPV6" Internet Protocol, version 6 (IETF RFC 2460)
718  * "IPV4V6" Virtual <PDP_type>introduced to handle dual IP stack UE capability (see 3GPP
719  *  TS 24.301[83])
720  *
721  * <APN>
722  * Access Point Name
723  *
724  * <PDP_address>
725  * It is the string parameter that identifies the MT in the address space applicable to the PDP
726  * The allocated address may be read using the command +CGPADDR command
727  *
728  * <d_comp>
729  * A numeric parameter that controls PDP data compression
730  * 0 off
731  * 1 on
732  * 2 V.42 bis
733  *
734  * <h_comp>
735  * A numeric parameter that controls PDP header compression
736  * 0 off
737  * 1 on
738  * 2 RFC1144
739  * 3 RFC2507
740  * 4 RFC3095
741  *
742  * <pd1>...<pdN>
743  * zero to N string parameters whose meanings are specific to the <PDP_type>
744  *
745  * Response -
746  * Success: (No Result)
747  *      OK
748  * Failure:
749  *      +CME ERROR: <error>
750  */
751 static TelReturn imc_ps_define_context(CoreObject *co_ps, CoreObject *ps_context,
752                                 TcoreObjectResponseCallback cb, void *cb_data)
753 {
754         TelReturn ret = TEL_RETURN_FAILURE;
755         gchar *at_cmd = NULL;
756         guint context_id = 0;
757         gchar *apn = NULL;
758         gchar *pdp_type_str = NULL;
759         TcoreContextType pdp_type;
760         TcoreContextDComp d_comp;
761         TcoreContextHComp h_comp;
762         TcorePsCallState curr_call_status;
763
764         PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
765
766         tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
767
768         dbg("Entred");
769
770         (void)tcore_context_get_id(ps_context, &context_id);
771         (void)tcore_context_get_type(ps_context, &pdp_type);
772
773         switch (pdp_type) {
774         case TCORE_CONTEXT_TYPE_X25:
775                 dbg("CONTEXT_TYPE_X25");
776                 pdp_type_str = g_strdup("X.25");
777         break;
778
779         case TCORE_CONTEXT_TYPE_IP:
780                 dbg("CONTEXT_TYPE_IP");
781                 pdp_type_str = g_strdup("IP");
782         break;
783
784         case TCORE_CONTEXT_TYPE_PPP:
785                 dbg("CONTEXT_TYPE_PPP");
786                 pdp_type_str = g_strdup("PPP");
787         break;
788
789         case TCORE_CONTEXT_TYPE_IPV6:
790                 dbg("CONTEXT_TYPE_IPV6");
791                 pdp_type_str = g_strdup("IPV6");
792                 break;
793
794         default:
795                 /*PDP Type not supported*/
796                 dbg("Unsupported PDP type: %d", pdp_type);
797                 goto error;
798         }
799
800         (void)tcore_context_get_data_compression(ps_context, &d_comp);
801         (void)tcore_context_get_header_compression(ps_context, &h_comp);
802         (void)tcore_context_get_apn(ps_context, &apn);
803
804         dbg("Define context for CID: %d", context_id);
805
806         /* AT-Command */
807         at_cmd = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", context_id, pdp_type_str, apn, d_comp, h_comp);
808         dbg("AT Command : %s", at_cmd);
809
810         /* Send Request to modem */
811         ret = tcore_at_prepare_and_send_request(co_ps,
812                 at_cmd, NULL,
813                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
814                 NULL,
815                 on_response_imc_ps_define_context,
816                 ps_context,
817                 on_send_imc_request, NULL);
818
819         tcore_free(pdp_type_str);
820         tcore_free(at_cmd);
821         tcore_free(apn);
822
823         if (ret == TEL_RETURN_SUCCESS)
824                 goto out;
825
826 error:
827         err("Failed to prepare and send AT request");
828
829         curr_call_status = private_info->ps_call_status;
830         __notify_context_status_changed(co_ps, context_id, curr_call_status);
831
832 out:
833         return ret;
834 }
835
836 /* PS Operations */
837 static TcorePsOps imc_ps_ops = {
838         .define_context = imc_ps_define_context,
839         .activate_context = imc_ps_activate_context,
840         .deactivate_context = imc_ps_deactivate_context
841 };
842
843
844 gboolean imc_ps_init(TcorePlugin *p, CoreObject *co)
845 {
846         PrivateInfo *private_info;
847
848         dbg("Entry");
849
850         /* Set PrivateInfo */
851         private_info = tcore_malloc0(sizeof(PrivateInfo));
852         tcore_object_link_user_data(co, private_info);
853
854         /* Set operations */
855         tcore_ps_set_ops(co, &imc_ps_ops);
856
857         /* Add Callbacks */
858         tcore_object_add_callback(co, "+CGEV", on_notification_imc_ps_cgev, NULL);
859
860         tcore_plugin_add_notification_hook(p,
861         TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS,
862         on_hook_imc_nw_registration_status, co);
863
864         dbg("Exit");
865         return TRUE;
866 }
867
868 void imc_ps_exit(TcorePlugin *p, CoreObject *co)
869 {
870         PrivateInfo *private_info;
871
872         private_info = tcore_object_ref_user_data(co);
873         tcore_check_return_assert(private_info != NULL);
874
875         tcore_free(private_info);
876
877         dbg("Exit");
878 }