merge with master
[platform/core/telephony/tel-plugin-imc.git] / src / s_ps.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Arun Shukla <arun.shukla@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <glib.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29
30 #include <tcore.h>
31 #include <hal.h>
32 #include <core_object.h>
33 #include <plugin.h>
34 #include <queue.h>
35 #include <co_ps.h>
36 #include <co_context.h>
37 #include <storage.h>
38 #include <server.h>
39 #include <at.h>
40 #include <util.h>
41 #include <type/ps.h>
42
43 #include "s_common.h"
44 #include "s_ps.h"
45
46
47
48 #define VNET_CH_PATH_BOOT0  "/dev/umts_boot0"
49 #define IOCTL_CG_DATA_SEND  _IO('o', 0x37)
50
51 /*Invalid Session ID*/
52 #define PS_INVALID_CID  999 /*Need to check */
53
54 /*Maximum String length Of the Command*/
55 #define MAX_AT_CMD_STR_LEN  150
56
57 /*Command for PDP activation and Deactivation*/
58 #define AT_PDP_ACTIVATE 1
59 #define AT_PDP_DEACTIVATE 0
60
61 #define AT_XDNS_ENABLE 1
62 #define AT_XDNS_DISABLE 0
63 #define AT_SESSION_DOWN 0
64 static void _ps_free(void *ptr)
65 {
66         dbg("Entered");
67         if (ptr) {
68                 (void) free(ptr);
69                 ptr = NULL;
70         }
71         dbg("Exit");
72         return;
73 }
74 static void _unable_to_get_pending(CoreObject *co_ps, CoreObject *ps_context)
75 {
76         struct tnoti_ps_call_status data_resp = {0};
77         dbg("Entered");
78         data_resp.context_id = tcore_context_get_id(ps_context);
79         data_resp.state = AT_SESSION_DOWN; /*check value of state*/
80         data_resp.result = 0xFF; /*check error value*/
81         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
82                                                                    TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), &data_resp);
83         (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
84         dbg("Exit");
85 }
86 static TReturn _pdp_device_control(unsigned int cid)
87 {
88         int fd = -1;
89         int ret = -1;
90         fd = open(VNET_CH_PATH_BOOT0, O_RDWR);
91         if (fd < 0) {
92                 dbg("error : open [ %s ] [ %s ]", VNET_CH_PATH_BOOT0, strerror(errno));
93                 return -1;
94         }
95         /*To Do for different Cids*/
96         dbg("Send IOCTL: arg 0x05 (0101) HSIC1, cid=%d \n", cid);
97         if (cid == 1) {
98                 ret = ioctl(fd, IOCTL_CG_DATA_SEND, 0x05);
99         } else if (cid == 2) {
100                 ret = ioctl(fd, IOCTL_CG_DATA_SEND, 0xA);
101         } else {
102                 dbg("More Than 2 context are not supported right Now");
103         }
104         close(fd);
105         if (ret < 0) {
106                 dbg("[ error ] send IOCTL_CG_DATA_SEND (0x%x) fail!! \n", IOCTL_CG_DATA_SEND);
107                 return TCORE_RETURN_FAILURE;
108         } else {
109                 dbg("[ ok ] send IOCTL_CG_DATA_SEND (0x%x) success!! \n", IOCTL_CG_DATA_SEND);
110                 return TCORE_RETURN_SUCCESS;
111         }
112 }
113
114 static gboolean on_event_cgev_handle(CoreObject *co_ps, const void *data, void *user_data)
115 {
116         char *token = NULL;
117         GSList *tokens = NULL;
118         GSList *lines = NULL;
119         const char *line = NULL;
120         char *noti_data = NULL;
121         int i = 0;
122         int value = 20;
123         int state = -1;
124         struct tnoti_ps_call_status data_resp = {0};
125
126         dbg("Entered");
127         lines = (GSList *) data;
128         line = (const char *) lines->data;
129         dbg("Lines->data :-%s", line);
130
131         tokens = tcore_at_tok_new(line);
132         switch (g_slist_length(tokens)) {
133         case 0:
134         {
135                 dbg("No token present: Ignore +CGEV Notifications ");
136                 return TRUE;
137         }
138
139         case 1:
140         {
141                 dbg("one Token present");
142                 noti_data = g_slist_nth_data(tokens, 0);
143                 dbg("notification data :-%s", noti_data);
144                 if (0 == strcmp(noti_data, "ME CLASS B")) {
145                         dbg("ME Class B notification received");
146                         goto ignore;
147                 }
148                 if (0 == strcmp(noti_data, "NW CLASS A")) {
149                         dbg("NW Class A notification received");
150                         goto ignore;
151                 }
152                 token = strtok(noti_data, " ");
153                 while (token != NULL) {
154                         if ((i == 0) && (0 != strcmp(token, "ME"))) {
155                                 break;
156                         }
157                         if ((i == 1) && (0 != strcmp(token, "PDN"))) {
158                                 break;
159                         }
160                         if ((i == 2) && (0 == strcmp(token, "ACT"))) {
161                                 state = 1;
162                         }
163                         if ((i == 2) && (0 == strcmp(token, "DEACT"))) {
164                                 state = 0;
165                         }
166                         if (i == 3) {
167                                 value = atoi(token);
168                                 break;
169                         }
170                         i++;
171                         token = strtok(NULL, " ");
172                 }
173                 dbg("value:%d ", value);
174                 i = 0;
175                 break;
176         }
177
178         case 3:
179         {
180                 i = 0;
181                 state = 0;
182                 value = 0;
183                 dbg("Three Token present");
184                 noti_data = g_slist_nth_data(tokens, 0);
185                 dbg("notification data :-%s", noti_data);
186                 token = strtok(noti_data, " ");
187                 while (token != NULL) {
188                         if ((i == 0) && (0 == strcmp(token, "ME"))) {
189                                 state = 1;
190                         }
191                         if ((i == 1) && (0 != strcmp(token, "DEACT"))) {
192                                 break;
193                         }
194                         if ((i == 2) && (0 == strcmp(token, "\"IP\"")) && (0 == state)) {
195                                 dbg("MObile Deactiavted the Context");
196                                 value = 10;
197                                 break;
198                         }
199                         if ((i == 2) && (0 == strcmp(token, "\"IP\"")) && (1 == state)) {
200                                 dbg("NW Deactiavted the Context");
201                                 value = 10;
202                                 break;
203                         }
204                         i++;
205                         token = strtok(NULL, " ");
206                 }
207                 if (value == 10 && state == 0) {
208                         dbg("Recieved Notification for Context deactivations from network");
209                         noti_data = g_slist_nth_data(tokens, 1);
210                         dbg("PDP Address :- %s", noti_data);
211                         noti_data = g_slist_nth_data(tokens, 2);
212                         dbg("CID got deactivated :- %d", atoi(noti_data));
213                 }
214                 if (value == 10 && state == 1) {
215                         dbg("Recieved Notification for Context deactivations from Mobile");
216                         noti_data = g_slist_nth_data(tokens, 1);
217                         dbg("PDP Address :- %s", noti_data);
218                         noti_data = g_slist_nth_data(tokens, 2);
219                         dbg("CID got deactivated :- %d", atoi(noti_data));
220                 }
221                 data_resp.context_id = atoi(noti_data);
222                 data_resp.state = 3;        /*check value of state*/
223                 dbg("State of the service :- %d", data_resp.state);
224                 data_resp.result = 0xFF;       /*check error value*/
225                 dbg("Sending the notification");
226
227                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
228                                                                            TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), &data_resp);
229
230                 state = 100;
231                 value = 100;
232
233                 break;
234         }
235
236         default:
237         {
238                 dbg("Ignore +CGEV Notifications ");
239         }
240         }
241         if (state == 1) {
242                 dbg("Notification recieved for Activation of CID:-%d", value);
243         } else if (state == 0) {
244                 dbg("Notification recieved for Deactivation of CID:-%d", value);
245         } else {
246                 dbg("ignore");
247         }
248 ignore:
249         tcore_at_tok_free(tokens);
250         return TRUE;
251 }
252
253 static gboolean on_event_dun_call_notification(CoreObject *o, const void *data, void *user_data)
254 {
255         GSList *tokens = NULL;
256         const char *line = NULL;
257         int value = 0;
258         GSList *lines = NULL;
259         dbg("Entered");
260
261         lines = (GSList *) data;
262         if (1 != g_slist_length(lines)) {
263                 dbg("unsolicited msg but multiple line");
264                 goto OUT;
265         }
266         line = (char *) (lines->data);
267         tokens = tcore_at_tok_new(line);
268         value = atoi(g_slist_nth_data(tokens, 0));
269
270         /*
271         <status> may be
272         0: DUN activation in progress
273         1: DUN deactivation in progress
274         2: DUN activated
275         3: DUN deactivated
276         */
277         switch (value) {
278         case 0:    /*Fall Through*/
279         case 1:
280         {
281                 break;
282         }
283
284         case 2:
285         {
286                 /*To Do:- Fill Data structure : data*/
287                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
288                                                                            TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
289         }
290
291         case 3:
292         {
293                 /*To Do:- Fill Data structure : data*/
294                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
295                                                                            TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
296         }
297         break;
298
299         default:
300                 goto OUT;
301         }
302 OUT:
303         if (NULL != tokens) {
304                 tcore_at_tok_free(tokens);
305         }
306         return TRUE;
307 }
308 static void on_response_undefine_context_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
309 {
310         CoreObject *co_ps = NULL;
311         const TcoreATResponse *resp = data;
312         CoreObject *ps_context = user_data;
313         dbg("Entered");
314         co_ps = tcore_pending_ref_core_object(p);
315         if (resp->success) {
316                 dbg("Response Ok");
317                 return;
318         }
319         dbg("Response NOk");
320         _unable_to_get_pending(co_ps, ps_context);
321         return;
322 }
323
324 static void send_undefine_context_cmd(CoreObject *co_ps, CoreObject *ps_context)
325 {
326         TcoreHal *hal = NULL;
327         TcorePending *pending = NULL;
328         char cmd_str[MAX_AT_CMD_STR_LEN];
329         int cid = 0;
330
331         dbg("Entered");
332         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
333
334         /* FIXME: Before MUX setup, use PHY HAL directly. */
335         hal = tcore_object_get_hal(co_ps);
336
337         /*Getting Context ID from Core Object*/
338         cid = tcore_context_get_id(ps_context);
339
340         (void) sprintf(cmd_str, "AT+CGDCONT=%d", cid);
341         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
342                                                                    on_response_undefine_context_cmd, ps_context);
343         if (NULL == pending) {
344                 err("Unable to get the create a AT request ");
345                 goto error;
346         }
347         tcore_hal_send_request(hal, pending);
348         dbg("Exit: Successfully");
349         return;
350 error:
351         {
352                 dbg("Exit: With error");
353                 _unable_to_get_pending(co_ps, ps_context);
354                 return;
355         }
356 }
357 static void on_response_data_counter_command(TcorePending *p, int data_len, const void *data, void *user_data)
358 {
359         CoreObject *ps_context = user_data;
360         const TcoreATResponse *resp = data;
361         CoreObject *co_ps = tcore_pending_ref_core_object(p);
362
363         GSList *tokens = NULL;
364         GSList *pRespData;
365         const char *line = NULL;
366         int no_pdp_active = 0;
367         unsigned long long Rx;
368         unsigned long long Tx;
369         int cid = tcore_context_get_id(ps_context);
370         dbg("Entered");
371
372         if (resp->final_response) {
373                 dbg("Response OK");
374                 dbg(" response lines : -%s", resp->lines);
375                 if (resp->lines) {
376                         pRespData = (GSList *) resp->lines;
377                         no_pdp_active = g_slist_length(pRespData);
378                         dbg("Total Number of Active PS Context :- %d", no_pdp_active);
379
380                         if (no_pdp_active == 0) {
381                                 return;
382                         }
383                         while (pRespData) {
384                                 dbg("Entered the Loop pRespData");
385
386                                 line = (const char *) pRespData->data;
387                                 dbg("Response->lines->data :%s", line);
388                                 tokens = tcore_at_tok_new(line);
389                                 if (cid == atoi(g_slist_nth_data(tokens, 0))) {
390                                         dbg("Found the data for our CID");
391                                         Tx = (unsigned long long) g_ascii_strtoull((g_slist_nth_data(tokens, 1)), NULL, 10);
392                                         dbg("Tx: %d", Tx);
393
394                                         Rx = (unsigned long long) g_ascii_strtoull((g_slist_nth_data(tokens, 2)), NULL, 10);
395                                         dbg("Rx: %d", Rx);
396
397                                         tcore_at_tok_free(tokens);
398                                         tokens = NULL;
399                                         dbg("Exiting the Loop pRespData");
400                                         break;
401                                 }
402                                 tcore_at_tok_free(tokens);
403                                 tokens = NULL;
404                                 pRespData = pRespData->next;
405                         }
406                         dbg("Sending Data counter notifications");
407
408                         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
409                                                                                    TNOTI_PS_CURRENT_SESSION_DATA_COUNTER, 0, NULL);
410                         return;
411                 } else {
412                         dbg("No Active PS Context");
413                 }
414         }
415         dbg("Response NOK");
416 }
417
418 static TReturn send_data_counter_command(CoreObject *co_ps, CoreObject *ps_context)
419 {
420         TcoreHal *hal = NULL;
421         TcorePending *pending = NULL;
422         char cmd_str[MAX_AT_CMD_STR_LEN];
423
424         dbg("Enetered");
425         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
426
427         hal = tcore_object_get_hal(co_ps);
428
429         (void) sprintf(cmd_str, "AT+XGCNTRD");
430         pending = tcore_at_pending_new(co_ps, cmd_str, "+XGCNTRD", TCORE_AT_MULTILINE,
431                                                                    on_response_data_counter_command, ps_context);
432         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
433                 return TCORE_RETURN_SUCCESS;
434         }
435         _unable_to_get_pending(co_ps, ps_context);
436         return TCORE_RETURN_FAILURE;
437 /*Add code if unable to get the data usage*/
438 }
439 static void on_response_deactivate_ps_context(TcorePending *p, int data_len, const void *data, void *user_data)
440 {
441         CoreObject *co_ps = tcore_pending_ref_core_object(p);
442         CoreObject *ps_context = user_data;
443         const TcoreATResponse *resp = data;
444         int cid;
445
446         cid = tcore_context_get_id(ps_context);
447         if (resp->success) {
448                 dbg("Response OK");
449                 /*get the data usage and report it application*/
450                 (void) send_data_counter_command(co_ps, ps_context);
451                 /*get the HSDPA status and report it to server*/
452         } else {
453                 dbg("Response NOK");
454                 send_undefine_context_cmd(co_ps, ps_context);
455         }
456         return;
457 }
458
459 static TReturn deactivate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
460 {
461         TcoreHal *hal = NULL;
462         TcorePending *pending = NULL;
463         unsigned int cid = PS_INVALID_CID;
464         char cmd_str[MAX_AT_CMD_STR_LEN];
465
466         dbg("Entered");
467         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
468
469         /*Getting Context ID from Core Object*/
470         cid = tcore_context_get_id(ps_context);
471
472         /* FIXME: Before MUX setup, use PHY HAL directly. */
473         hal = tcore_object_get_hal(co_ps);
474         if(FALSE == tcore_hal_get_power_state(hal)){
475                 dbg("cp not ready/n");
476                 return TCORE_RETURN_ENOSYS;
477         }
478
479         (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_DEACTIVATE, cid);
480         dbg("At commands :- %s", cmd_str);
481
482         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
483                                                                    on_response_deactivate_ps_context, ps_context);
484         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
485                 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATING);
486                 return TCORE_RETURN_SUCCESS;
487         }
488         _unable_to_get_pending(co_ps, ps_context);
489         return TCORE_RETURN_FAILURE;
490 }
491
492 static void on_response_get_dns_cmnd(TcorePending *p, int data_len, const void *data, void *user_data)
493 {
494         struct tnoti_ps_pdp_ipconfiguration noti = {0};
495         struct tnoti_ps_call_status data_status = {0};
496         char devname[10] = {0, };
497         char *dns_prim = NULL;
498         char *dns_sec = NULL;
499         char *pdp_address = NULL;
500         char addr[4] = {0};
501         GSList *tokens = NULL;
502         GSList *pRespData;
503         const char *line = NULL;
504         char *token_dns = NULL;
505         char *token_add = NULL;
506
507         char *token_pdp_address = NULL;
508         int no_pdp_active = 0;
509         int index = 0;
510
511         CoreObject *ps_context = user_data;
512         const TcoreATResponse *resp = data;
513         CoreObject *co_ps = tcore_pending_ref_core_object(p);
514         int cid = tcore_context_get_id(ps_context);
515
516         dbg("Entered");
517
518         if (resp->final_response) {
519                 dbg("Response OK");
520                 if (resp->lines) {
521                         dbg("DNS data present in the Response");
522                         pRespData = (GSList *) resp->lines;
523                         no_pdp_active = g_slist_length(pRespData);
524                         dbg("Total Number of Active PS Context :- %d", no_pdp_active);
525                         if (0 == no_pdp_active) {
526                                 goto exit_fail;
527                         }
528                         while (pRespData) {
529                                 dbg("traversing the DNS data for each active context");
530                                 line = (const char *) pRespData->data;
531                                 dbg("Response->lines->data :%s", line);
532                                 tokens = tcore_at_tok_new(line);
533                                 if (cid == atoi(g_slist_nth_data(tokens, 0))) {
534                                         dbg("Found the DNS details for the Current context");
535                                         dbg("Context Id of The Context : %d", atoi(g_slist_nth_data(tokens, 0)));
536                                         break;
537                                 }
538                                 tcore_at_tok_free(tokens);
539                                 tokens = NULL;
540                                 pRespData = pRespData->next;
541                         }
542                         { /* Read primary DNS */
543                                 token_dns = g_slist_nth_data(tokens, 1);
544                                 /* Strip off starting " and ending " from this token to read actual PDP address */
545                                 dns_prim = util_removeQuotes((void *) token_dns);
546                                 dbg("Token_dns :%s", token_dns);
547                                 dbg("Primary DNS :- %s", dns_prim);
548                                 index = 0;
549                                 token_add = strtok(dns_prim, ".");
550                                 while (token_add != NULL) {
551                                         noti.primary_dns[index++] = atoi(token_add);
552                                         token_add = strtok(NULL, ".");
553                                 }
554                                 _ps_free(dns_prim);
555                         }
556                         { /* Read Secondary DNS */
557                                 token_add = NULL;
558                                 token_dns = g_slist_nth_data(tokens, 2);
559                                 dns_sec = util_removeQuotes((void *) token_dns);
560
561                                 dbg("Token_dns :%s", token_dns);
562                                 dbg("Secondary DNS :- %s", dns_sec);
563                                 index = 0;
564                                 token_add = strtok(dns_sec, ".");
565                                 while (token_add != NULL) {
566                                         noti.secondary_dns[index++] = atoi(token_add);
567                                         token_add = strtok(NULL, ".");
568                                 }
569                                 _ps_free(dns_sec);
570                         }
571                         tcore_at_tok_free(tokens);
572                         tokens = NULL;
573                         goto exit_success;
574                 } else {
575                         dbg("No data present in the Response");
576                 }
577         }
578         dbg("Response NOK");
579 exit_fail:
580         {
581                 dbg("Adding default DNS");
582                 dbg("Adding the Primary DNS");
583                 noti.primary_dns[0] = 8;
584                 noti.primary_dns[1] = 8;
585                 noti.primary_dns[2] = 8;
586                 noti.primary_dns[3] = 8;
587                 dbg("Adding Secondary DNS");
588                 noti.secondary_dns[0] = 8;
589                 noti.secondary_dns[1] = 8;
590                 noti.secondary_dns[2] = 4;
591                 noti.secondary_dns[3] = 4;
592         }
593 exit_success:
594         {
595                 dbg("Able to get the DNS from the DNS Query");
596                 token_pdp_address = tcore_context_get_address(ps_context);
597                 pdp_address = util_removeQuotes((void *) token_pdp_address);
598
599                 dbg("PDP address :- %s", pdp_address);
600                 /* Store IP address in char array, Telephony expected IP address in this format */
601                 token_add = strtok(pdp_address, ".");
602                 index = 0;
603                 while ((token_add != NULL) && (index < 4)) {   /* Currently only IPv4 is supported */
604                         addr[index++] = atoi(token_add);
605                         token_add = strtok(NULL, ".");
606                 }
607                 _ps_free(pdp_address);
608                 _ps_free((void *) token_pdp_address);
609                 noti.field_flag = (0x0001 & 0x0002 & 0x0004);
610                 noti.err = 0;
611                 noti.context_id = cid;
612                 memcpy(&noti.ip_address, &addr, 4);
613                 if (_pdp_device_control(cid) != TCORE_RETURN_SUCCESS) {
614                         dbg("_pdp_device_control() failed. errno=%d", errno);
615                 }
616                 snprintf(devname, 10, "pdp%d", cid - 1);
617                 memcpy(noti.devname, devname, 10);
618                 dbg("devname = [%s]", devname);
619                 if (tcore_util_netif_up(devname) != TCORE_RETURN_SUCCESS) {
620                         dbg("util_netif_up() failed. errno=%d", errno);
621                 }
622
623                 dbg("Send Notification upwards of IP address");
624                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps, TNOTI_PS_PDP_IPCONFIGURATION,
625                                                                            sizeof(struct tnoti_ps_pdp_ipconfiguration), &noti);
626
627                 data_status.context_id = cid;
628                 data_status.state = 1;
629                 data_status.result = 0;
630
631                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
632                                                                            TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), &data_status);
633                 dbg("EXIT : Without error");
634                 return;
635         }
636 }
637
638 static TReturn send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
639 {
640         TcoreHal *hal = NULL;
641         TcorePending *pending = NULL;
642         char cmd_str[MAX_AT_CMD_STR_LEN];
643
644         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
645
646         dbg("Entered");
647         hal = tcore_object_get_hal(co_ps);
648
649         (void) sprintf(cmd_str, "AT+XDNS?");
650         pending = tcore_at_pending_new(co_ps, cmd_str, "+XDNS", TCORE_AT_MULTILINE,
651                                                                    on_response_get_dns_cmnd, ps_context);
652         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
653                 return TCORE_RETURN_SUCCESS;
654         }
655         _unable_to_get_pending(co_ps, ps_context);
656         return TCORE_RETURN_FAILURE;
657 }
658
659 static void on_response_get_pdp_address(TcorePending *p, int data_len, const void *data, void *user_data)
660 {
661         const TcoreATResponse *resp = data;
662         CoreObject *co_ps = tcore_pending_ref_core_object(p);
663         CoreObject *ps_context = user_data;
664         GSList *tokens = NULL;
665         const char *line;
666         char *token_pdp_address;
667         dbg("Enetered");
668         if (resp->final_response) {
669                 dbg("RESPONSE OK");
670                 if (resp->lines != NULL) {
671                         dbg("resp->lines present ");
672                         line = (const char *) resp->lines->data;
673                         tokens = tcore_at_tok_new(line);
674                         if (g_slist_length(tokens) < 2) {
675                                 msg("invalid message");
676                                 goto error;
677                         }
678                         dbg("line:- %s", line);
679                         /* CID is already stored in ps_context, skip over & read PDP address */
680                         token_pdp_address = g_slist_nth_data(tokens, 1);
681
682                         dbg("token_pdp_address :- %s", token_pdp_address);
683                         /* Strip off starting " and ending " from this token to read actual PDP address */
684                         (void) tcore_context_set_address(ps_context, (const char *) token_pdp_address);
685                 }
686
687                 (void) send_get_dns_cmd(co_ps, ps_context);
688         } else {
689                 dbg("Response NOK");
690                 /*without PDP address we will not be able to start packet service*/
691                 (void) deactivate_ps_context(co_ps, ps_context, NULL);
692         }
693 error:
694         tcore_at_tok_free(tokens);
695         return;
696 }
697
698 static TReturn send_get_pdp_address_cmd(CoreObject *co_ps, CoreObject *ps_context)
699 {
700         TcoreHal *hal = NULL;
701         TcorePending *pending = NULL;
702         unsigned int cid = PS_INVALID_CID;
703         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
704
705         dbg("Entered");
706         hal = tcore_object_get_hal(co_ps);
707
708         cid = tcore_context_get_id(ps_context);
709         (void) sprintf(cmd_str, "AT+CGPADDR=%d", cid);
710         pending = tcore_at_pending_new(co_ps, cmd_str, "+CGPADDR", TCORE_AT_SINGLELINE,
711                                                                    on_response_get_pdp_address, ps_context);
712         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
713                 return TCORE_RETURN_SUCCESS;
714         }
715         _unable_to_get_pending(co_ps, ps_context);
716         return TCORE_RETURN_FAILURE;
717 }
718
719 static void on_response_send_pdp_activate_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
720 {
721         CoreObject *co_ps = NULL;
722         const TcoreATResponse *resp = data;
723         CoreObject *ps_context = user_data;
724
725         int cid;
726         cid = tcore_context_get_id(ps_context);
727
728
729         dbg("Entered");
730         if (!p) {
731                 goto error;
732         }
733         co_ps = tcore_pending_ref_core_object(p);
734
735         if (resp->success) {
736                 dbg("Response Ok");
737                 /*getting the IP address and DNS from the modem*/
738                 dbg("Getting the IP Address");
739                 (void) send_get_pdp_address_cmd(co_ps, ps_context);
740                 return;
741         } else {
742                 dbg("Unable to actiavte PDP context for CID: %d ", cid);
743                 dbg("Undefineing the PDP context");
744                 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
745                 send_undefine_context_cmd(co_ps, ps_context);
746                 return;
747         }
748 error:
749         {
750                 _unable_to_get_pending(co_ps, ps_context);
751                 return;
752         }
753 }
754
755 static TReturn send_pdp_activate_cmd(CoreObject *co_ps, CoreObject *ps_context)
756 {
757         TcoreHal *hal = NULL;
758         TcorePending *pending = NULL;
759         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
760         int cid = 0;
761         dbg("Entered");
762         /* FIXME: Before MUX setup, use PHY HAL directly. */
763         hal = tcore_object_get_hal(co_ps);
764
765         /*Getting Context ID from Core Object*/
766         cid = tcore_context_get_id(ps_context);
767         (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_ACTIVATE, cid);
768         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
769                                                                    on_response_send_pdp_activate_cmd, ps_context);
770         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
771                 return TCORE_RETURN_SUCCESS;
772         }
773         _unable_to_get_pending(co_ps, ps_context);
774         return TCORE_RETURN_FAILURE;
775 }
776
777 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
778 {
779         dbg("Entered");
780         return send_pdp_activate_cmd(co_ps, ps_context);
781 }
782
783 static void on_response_xdns_enable_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
784 {
785         TcoreATResponse *resp = (TcoreATResponse *) data;
786         CoreObject *co_ps = tcore_pending_ref_core_object(p);
787         CoreObject *ps_context = user_data;
788         struct tnoti_ps_call_status noti = {0};
789         int cid = -1;
790         
791         dbg("Entered");
792
793         cid = tcore_context_get_id(ps_context);
794         
795         if (resp->success) {
796                 dbg("Response OK");
797                 dbg("DNS address getting is Enabled");          
798                 noti.context_id = cid;
799                 noti.state = 0;
800                 noti.result = 0;
801         } else {
802                 dbg("Response NOK");            
803                 noti.context_id = cid;
804                 noti.state = 3;
805                 noti.result = 0;
806                 /*If response to enable the DNS NOK then we will use google DNS for the PDP context*/
807         }
808
809         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
810                                                                    TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), &noti);
811         return;
812 }
813
814 static TReturn send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
815 {
816         TcoreHal *hal = NULL;
817         TcorePending *pending = NULL;
818         int cid = -1;
819         char cmd_str[MAX_AT_CMD_STR_LEN];
820
821         dbg("Entered");
822         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
823
824         hal = tcore_object_get_hal(co_ps);
825         cid = tcore_context_get_id(ps_context);
826
827         (void) sprintf(cmd_str, "AT+XDNS=%d,%d", cid, AT_XDNS_ENABLE);
828         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
829                                                                    on_response_xdns_enable_cmd, ps_context);
830         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
831                 return TCORE_RETURN_SUCCESS;
832         }
833         _unable_to_get_pending(co_ps, ps_context);
834         return TCORE_RETURN_FAILURE;
835 }
836
837 static void on_response_define_pdp_context(TcorePending *p, int data_len, const void *data, void *user_data)
838 {
839         const TcoreATResponse *resp = data;
840         CoreObject *ps_context = (CoreObject *) user_data;
841         CoreObject *co_ps = tcore_pending_ref_core_object(p);
842
843         dbg("Entered");
844         if (resp->success) {
845                 dbg("Response OK");
846                 send_xdns_enable_cmd(co_ps, ps_context);
847         } else {
848                 dbg("response NOK");
849                 _unable_to_get_pending(co_ps, ps_context);
850                 dbg("Exiting");
851         }
852         return;
853 }
854
855 static TReturn send_define_pdp_context_cmd(CoreObject *co_ps, CoreObject *ps_context)
856 {
857         TcoreHal *hal = NULL;
858         TcorePending *pending = NULL;
859         char *apn = NULL;
860         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
861         char pdp_type_str[10] = {0};
862         unsigned int cid = PS_INVALID_CID;
863         enum co_context_type pdp_type;
864         enum co_context_d_comp d_comp;
865         enum co_context_h_comp h_comp;
866
867         dbg("Entered");
868
869         cid = tcore_context_get_id(ps_context);
870         pdp_type = tcore_context_get_type(ps_context);
871         d_comp = tcore_context_get_data_compression(ps_context);
872         h_comp = tcore_context_get_header_compression(ps_context);
873         apn = tcore_context_get_apn(ps_context);
874
875         hal = tcore_object_get_hal(co_ps);
876         switch (pdp_type) {
877         case CONTEXT_TYPE_X25:
878         {
879                 dbg("CONTEXT_TYPE_X25");
880                 strcpy(pdp_type_str, "X.25");
881                 break;
882         }
883
884         case CONTEXT_TYPE_IP:
885         {
886                 dbg("CONTEXT_TYPE_IP");
887                 strcpy(pdp_type_str, "IP");
888         }
889         break;
890
891         case CONTEXT_TYPE_PPP:
892         {
893                 dbg("CONTEXT_TYPE_PPP");
894                 strcpy(pdp_type_str, "PPP");
895         }
896         break;
897
898         case CONTEXT_TYPE_IPV6:
899         {
900                 dbg("CONTEXT_TYPE_IPV6");
901                 strcpy(pdp_type_str, "IPV6");
902                 break;
903         }
904
905         default:
906         {
907                 /*PDP Type not supported supported*/
908                 dbg("Unsupported PDP type :- %d returning ", pdp_type);
909                 return TCORE_RETURN_FAILURE;
910         }
911         }
912         dbg("Activating context for CID :- %d", cid);
913         (void) sprintf(cmd_str, "AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid, pdp_type_str, apn, d_comp, h_comp);
914
915         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
916                                                                    on_response_define_pdp_context, ps_context);
917         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
918                 return TCORE_RETURN_SUCCESS;
919         }
920         _unable_to_get_pending(co_ps, ps_context);
921         return TCORE_RETURN_FAILURE;
922 }
923
924 static TReturn define_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
925 {
926         dbg("Entered");
927
928         if(FALSE == tcore_hal_get_power_state(tcore_object_get_hal(co_ps))){
929                 dbg("cp not ready/n");
930                 return TCORE_RETURN_ENOSYS;
931         }
932         return send_define_pdp_context_cmd(co_ps, ps_context);
933 }
934
935
936 static struct tcore_ps_operations ps_ops = {
937         .define_context = define_ps_context,
938         .activate_context = activate_ps_context,
939         .deactivate_context = deactivate_ps_context
940 };
941
942 gboolean s_ps_init(TcorePlugin *p, TcoreHal *hal)
943 {
944         CoreObject *o;
945         struct context *context_table = NULL;
946
947         dbg("Entered");
948         o = tcore_ps_new(p, "umts_ps", &ps_ops, hal);
949
950         if (!o)
951                 return FALSE;
952         tcore_object_link_user_data(o, (void *) context_table);
953
954         tcore_object_add_callback(o, "+CGEV", on_event_cgev_handle, p);
955         tcore_object_add_callback(o, "+XNOTIFYDUNSTATUS", on_event_dun_call_notification, p);
956
957         dbg("Exiting");
958         return TRUE;
959 }
960
961 void s_ps_exit(TcorePlugin *p)
962 {
963         CoreObject *o;
964
965         dbg("Entered");
966         o = tcore_plugin_ref_core_object(p, "umts_ps");
967         if (!o)
968                 return;
969
970         tcore_ps_free(o);
971         dbg("Exiting");
972 }