s-modem: replace "+XSIM:" unsolicited message handling with SIM status notification...
[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 /*Invalid Session ID*/
47 #define PS_INVALID_CID  999 /*Need to check */
48
49 /*Maximum String length Of the Command*/
50 #define MAX_AT_CMD_STR_LEN  150
51
52 /*Command for PDP activation and Deactivation*/
53 #define AT_PDP_ACTIVATE 1
54 #define AT_PDP_DEACTIVATE 0
55
56 #define AT_XDNS_ENABLE 1
57 #define AT_XDNS_DISABLE 0
58 #define AT_SESSION_DOWN 0
59
60 static void _ps_free(void *ptr)
61 {
62         dbg("Entered");
63         if (ptr) {
64                 (void) free(ptr);
65                 ptr = NULL;
66         }
67         dbg("Exit");
68         return;
69 }
70 static void _unable_to_get_pending(CoreObject *co_ps, CoreObject *ps_context)
71 {
72         struct tnoti_ps_call_status data_resp = {0};
73         dbg("Entered");
74         data_resp.context_id = tcore_context_get_id(ps_context);
75         data_resp.state = PS_DATA_CALL_NOT_CONNECTED; /*check value of state*/
76         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
77                                                                    TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), &data_resp);
78         (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
79         dbg("Exit");
80 }
81
82 static gboolean on_event_dun_call_notification(CoreObject *o, const void *data, void *user_data)
83 {
84         GSList *tokens = NULL;
85         const char *line = NULL;
86         int value = 0;
87         GSList *lines = NULL;
88         dbg("Entered");
89
90         lines = (GSList *) data;
91         if (1 != g_slist_length(lines)) {
92                 dbg("unsolicited msg but multiple line");
93                 goto OUT;
94         }
95         line = (char *) (lines->data);
96         tokens = tcore_at_tok_new(line);
97         value = atoi(g_slist_nth_data(tokens, 0));
98
99         /*
100         <status> may be
101         0: DUN activation in progress
102         1: DUN deactivation in progress
103         2: DUN activated
104         3: DUN deactivated
105         */
106         switch (value) {
107         case 0:    /*Fall Through*/
108         case 1:
109         {
110                 break;
111         }
112
113         case 2:
114         {
115                 /*To Do:- Fill Data structure : data*/
116                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
117                                                                            TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
118         }
119
120         case 3:
121         {
122                 /*To Do:- Fill Data structure : data*/
123                 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
124                                                                            TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
125         }
126         break;
127
128         default:
129                 goto OUT;
130         }
131 OUT:
132         if (NULL != tokens) {
133                 tcore_at_tok_free(tokens);
134         }
135         return TRUE;
136 }
137 static void on_response_undefine_context_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
138 {
139         CoreObject *co_ps = NULL;
140         const TcoreATResponse *resp = data;
141         CoreObject *ps_context = user_data;
142         dbg("Entered");
143         co_ps = tcore_pending_ref_core_object(p);
144         if (resp->success) {
145                 dbg("Response Ok");
146                 return;
147         }
148         dbg("Response NOk");
149         _unable_to_get_pending(co_ps, ps_context);
150         return;
151 }
152
153 static void send_undefine_context_cmd(CoreObject *co_ps, CoreObject *ps_context)
154 {
155         TcoreHal *hal = NULL;
156         TcorePending *pending = NULL;
157         char cmd_str[MAX_AT_CMD_STR_LEN];
158         int cid = 0;
159
160         dbg("Entered");
161         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
162
163         /* FIXME: Before MUX setup, use PHY HAL directly. */
164         hal = tcore_object_get_hal(co_ps);
165
166         /*Getting Context ID from Core Object*/
167         cid = tcore_context_get_id(ps_context);
168
169         (void) sprintf(cmd_str, "AT+CGDCONT=%d", cid);
170         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
171                                                                    on_response_undefine_context_cmd, ps_context);
172         if (NULL == pending) {
173                 err("Unable to get the create a AT request ");
174                 goto error;
175         }
176         tcore_hal_send_request(hal, pending);
177         dbg("Exit: Successfully");
178         return;
179 error:
180         {
181                 dbg("Exit: With error");
182                 _unable_to_get_pending(co_ps, ps_context);
183                 return;
184         }
185 }
186
187 static void on_setup_pdp(CoreObject *co_ps, const char *netif_name,
188                                 void *user_data)
189 {
190         CoreObject *ps_context = user_data;
191         struct tnoti_ps_call_status data_status = {0};
192         Server *server;
193
194         dbg("Enter");
195
196         dbg("devname = [%s]", netif_name);
197
198         tcore_context_set_ipv4_devname(ps_context, netif_name);
199
200         server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
201
202         data_status.context_id = tcore_context_get_id(ps_context);
203         data_status.state = PS_DATA_CALL_CONNECTED;
204
205         tcore_server_send_notification(server, co_ps,
206                                         TNOTI_PS_CALL_STATUS,
207                                         sizeof(struct tnoti_ps_call_status),
208                                         &data_status);
209
210         dbg("Exit");
211 }
212
213 static void on_response_get_dns_cmnd(TcorePending *p, int data_len, const void *data, void *user_data)
214 {
215         GSList *tokens = NULL;
216         GSList *pRespData;
217         const char *line = NULL;
218         char *dns_prim = NULL;
219         char *dns_sec = NULL;
220         char *token_dns = NULL;
221         int no_pdp_active = 0;
222         CoreObject *ps_context = user_data;
223         const TcoreATResponse *resp = data;
224         CoreObject *co_ps = tcore_pending_ref_core_object(p);
225         int cid = tcore_context_get_id(ps_context);
226         TcoreHal *h = tcore_object_get_hal(co_ps);
227
228         dbg("Entered");
229
230         if (resp->final_response) {
231                 dbg("Response OK");
232                 if (resp->lines) {
233                         dbg("DNS data present in the Response");
234                         pRespData = (GSList *) resp->lines;
235                         no_pdp_active = g_slist_length(pRespData);
236                         dbg("Total Number of Active PS Context :- %d", no_pdp_active);
237                         if (0 == no_pdp_active) {
238                                 goto exit_fail;
239                         }
240                         while (pRespData) {
241                                 dbg("traversing the DNS data for each active context");
242                                 line = (const char *) pRespData->data;
243                                 dbg("Response->lines->data :%s", line);
244                                 tokens = tcore_at_tok_new(line);
245                                 if (cid == atoi(g_slist_nth_data(tokens, 0))) {
246                                         dbg("Found the DNS details for the Current context");
247                                         dbg("Context Id of The Context : %d", atoi(g_slist_nth_data(tokens, 0)));
248                                         break;
249                                 }
250                                 tcore_at_tok_free(tokens);
251                                 tokens = NULL;
252                                 pRespData = pRespData->next;
253                         }
254                         { /* Read primary DNS */
255                                 token_dns = g_slist_nth_data(tokens, 1);
256                                 /* Strip off starting " and ending " from this token to read actual PDP address */
257                                 dns_prim = util_removeQuotes((void *) token_dns);
258                                 dbg("Token_dns :%s", token_dns);
259                                 dbg("Primary DNS :- %s", dns_prim);
260                         }
261                         { /* Read Secondary DNS */
262                                 token_dns = g_slist_nth_data(tokens, 2);
263                                 dns_sec = util_removeQuotes((void *) token_dns);
264
265                                 dbg("Token_dns :%s", token_dns);
266                                 dbg("Secondary DNS :- %s", dns_sec);
267                         }
268
269                         tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
270                         _ps_free(dns_prim);
271                         _ps_free(dns_sec);
272
273                         tcore_at_tok_free(tokens);
274                         tokens = NULL;
275                         goto exit_success;
276                 } else {
277                         dbg("No data present in the Response");
278                 }
279         }
280         dbg("Response NOK");
281 exit_fail:
282         {
283                 dbg("Adding default DNS");
284
285                 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
286         }
287 exit_success:
288         {
289                 /* mount network interface */
290                 if (tcore_hal_setup_netif(h, co_ps, on_setup_pdp, ps_context, cid, TRUE)
291                                 != TCORE_RETURN_SUCCESS) {
292                         err("Setup network interface failed");
293                         return;
294                 }
295
296                 dbg("EXIT : Without error");
297         }
298 }
299
300 static TReturn send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
301 {
302         TcoreHal *hal = NULL;
303         TcorePending *pending = NULL;
304         char cmd_str[MAX_AT_CMD_STR_LEN];
305
306         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
307
308         dbg("Entered");
309         hal = tcore_object_get_hal(co_ps);
310
311         (void) sprintf(cmd_str, "AT+XDNS?");
312         pending = tcore_at_pending_new(co_ps, cmd_str, "+XDNS", TCORE_AT_MULTILINE,
313                                                                    on_response_get_dns_cmnd, ps_context);
314         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
315                 return TCORE_RETURN_SUCCESS;
316         }
317         _unable_to_get_pending(co_ps, ps_context);
318         return TCORE_RETURN_FAILURE;
319 }
320
321 static void on_response_get_pdp_address(TcorePending *p, int data_len, const void *data, void *user_data)
322 {
323         const TcoreATResponse *resp = data;
324         CoreObject *co_ps = tcore_pending_ref_core_object(p);
325         CoreObject *ps_context = user_data;
326         GSList *tokens = NULL;
327         const char *line;
328         char *token_pdp_address;
329         dbg("Enetered");
330         if (resp->final_response) {
331                 dbg("RESPONSE OK");
332                 if (resp->lines != NULL) {
333                         dbg("resp->lines present ");
334                         line = (const char *) resp->lines->data;
335                         tokens = tcore_at_tok_new(line);
336                         if (g_slist_length(tokens) < 2) {
337                                 msg("invalid message");
338                                 goto error;
339                         }
340                         dbg("line:- %s", line);
341                         /* CID is already stored in ps_context, skip over & read PDP address */
342                         token_pdp_address = g_slist_nth_data(tokens, 1);
343
344                         dbg("token_pdp_address :- %s", token_pdp_address);
345                         /* Strip off starting " and ending " from this token to read actual PDP address */
346                         (void) tcore_context_set_ipv4_addr(ps_context, (const char *)token_pdp_address);
347                 }
348
349                 (void) send_get_dns_cmd(co_ps, ps_context);
350         } else {
351                 dbg("Response NOK");
352                 /*without PDP address we will not be able to start packet service*/
353                 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
354         }
355 error:
356         tcore_at_tok_free(tokens);
357         return;
358 }
359
360 static TReturn send_get_pdp_address_cmd(CoreObject *co_ps, CoreObject *ps_context)
361 {
362         TcoreHal *hal = NULL;
363         TcorePending *pending = NULL;
364         unsigned int cid = PS_INVALID_CID;
365         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
366
367         dbg("Entered");
368         hal = tcore_object_get_hal(co_ps);
369
370         cid = tcore_context_get_id(ps_context);
371         (void) sprintf(cmd_str, "AT+CGPADDR=%d", cid);
372         pending = tcore_at_pending_new(co_ps, cmd_str, "+CGPADDR", TCORE_AT_SINGLELINE,
373                                                                    on_response_get_pdp_address, ps_context);
374         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
375                 return TCORE_RETURN_SUCCESS;
376         }
377         _unable_to_get_pending(co_ps, ps_context);
378         return TCORE_RETURN_FAILURE;
379 }
380
381 static void on_response_send_pdp_activate_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
382 {
383         CoreObject *co_ps = NULL;
384         const TcoreATResponse *resp = data;
385         CoreObject *ps_context = user_data;
386
387         int cid;
388         cid = tcore_context_get_id(ps_context);
389
390
391         dbg("Entered");
392         if (!p) {
393                 goto error;
394         }
395         co_ps = tcore_pending_ref_core_object(p);
396
397         if (resp->success) {
398                 dbg("Response Ok");
399                 /*getting the IP address and DNS from the modem*/
400                 dbg("Getting the IP Address");
401                 (void) send_get_pdp_address_cmd(co_ps, ps_context);
402                 return;
403         } else {
404                 dbg("Unable to actiavte PDP context for CID: %d ", cid);
405                 dbg("Undefineing the PDP context");
406                 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
407                 send_undefine_context_cmd(co_ps, ps_context);
408                 return;
409         }
410 error:
411         {
412                 _unable_to_get_pending(co_ps, ps_context);
413                 return;
414         }
415 }
416
417 static TReturn send_pdp_activate_cmd(CoreObject *co_ps, CoreObject *ps_context)
418 {
419         TcoreHal *hal = NULL;
420         TcorePending *pending = NULL;
421         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
422         int cid = 0;
423         dbg("Entered");
424         /* FIXME: Before MUX setup, use PHY HAL directly. */
425         hal = tcore_object_get_hal(co_ps);
426
427         /*Getting Context ID from Core Object*/
428         cid = tcore_context_get_id(ps_context);
429         (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_ACTIVATE, cid);
430         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
431                                                                    on_response_send_pdp_activate_cmd, 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 }
438
439 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
440 {
441         dbg("Entered");
442         return send_pdp_activate_cmd(co_ps, ps_context);
443 }
444
445 static void on_response_xdns_enable_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
446 {
447         TcoreATResponse *resp = (TcoreATResponse *) data;
448         CoreObject *co_ps = tcore_pending_ref_core_object(p);
449         CoreObject *ps_context = user_data;
450         struct tnoti_ps_call_status noti = {0};
451         int cid = -1;
452         
453         dbg("Entered");
454
455         cid = tcore_context_get_id(ps_context);
456         
457         if (resp->success) {
458                 dbg("Response OK");
459                 dbg("DNS address getting is Enabled");          
460                 noti.context_id = cid;
461                 noti.state = PS_DATA_CALL_CTX_DEFINED;
462         } else {
463                 dbg("Response NOK");            
464                 noti.context_id = cid;
465                 noti.state = PS_DATA_CALL_NOT_CONNECTED;
466                 /*If response to enable the DNS NOK then we will use google DNS for the PDP context*/
467         }
468
469         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
470                                                                    TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), &noti);
471         return;
472 }
473
474 static TReturn send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
475 {
476         TcoreHal *hal = NULL;
477         TcorePending *pending = NULL;
478         int cid = -1;
479         char cmd_str[MAX_AT_CMD_STR_LEN];
480
481         dbg("Entered");
482         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
483
484         hal = tcore_object_get_hal(co_ps);
485         cid = tcore_context_get_id(ps_context);
486
487         (void) sprintf(cmd_str, "AT+XDNS=%d,%d", cid, AT_XDNS_ENABLE);
488         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
489                                                                    on_response_xdns_enable_cmd, ps_context);
490         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
491                 return TCORE_RETURN_SUCCESS;
492         }
493         _unable_to_get_pending(co_ps, ps_context);
494         return TCORE_RETURN_FAILURE;
495 }
496
497 static void on_response_define_pdp_context(TcorePending *p, int data_len, const void *data, void *user_data)
498 {
499         const TcoreATResponse *resp = data;
500         CoreObject *ps_context = (CoreObject *) user_data;
501         CoreObject *co_ps = tcore_pending_ref_core_object(p);
502
503         dbg("Entered");
504         if (resp->success) {
505                 dbg("Response OK");
506                 send_xdns_enable_cmd(co_ps, ps_context);
507         } else {
508                 dbg("response NOK");
509                 _unable_to_get_pending(co_ps, ps_context);
510                 dbg("Exiting");
511         }
512         return;
513 }
514
515 static TReturn define_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
516 {
517         TcoreHal *hal = NULL;
518         TcorePending *pending = NULL;
519         char *apn = NULL;
520         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
521         char pdp_type_str[10] = {0};
522         unsigned int cid = PS_INVALID_CID;
523         enum co_context_type pdp_type;
524         enum co_context_d_comp d_comp;
525         enum co_context_h_comp h_comp;
526
527         dbg("Entered");
528
529         cid = tcore_context_get_id(ps_context);
530         pdp_type = tcore_context_get_type(ps_context);
531         d_comp = tcore_context_get_data_compression(ps_context);
532         h_comp = tcore_context_get_header_compression(ps_context);
533         apn = tcore_context_get_apn(ps_context);
534
535         hal = tcore_object_get_hal(co_ps);
536         switch (pdp_type) {
537         case CONTEXT_TYPE_X25:
538         {
539                 dbg("CONTEXT_TYPE_X25");
540                 strcpy(pdp_type_str, "X.25");
541                 break;
542         }
543
544         case CONTEXT_TYPE_IP:
545         {
546                 dbg("CONTEXT_TYPE_IP");
547                 strcpy(pdp_type_str, "IP");
548         }
549         break;
550
551         case CONTEXT_TYPE_PPP:
552         {
553                 dbg("CONTEXT_TYPE_PPP");
554                 strcpy(pdp_type_str, "PPP");
555         }
556         break;
557
558         case CONTEXT_TYPE_IPV6:
559         {
560                 dbg("CONTEXT_TYPE_IPV6");
561                 strcpy(pdp_type_str, "IPV6");
562                 break;
563         }
564
565         default:
566         {
567                 /*PDP Type not supported supported*/
568                 dbg("Unsupported PDP type :- %d returning ", pdp_type);
569                 return TCORE_RETURN_FAILURE;
570         }
571         }
572         dbg("Activating context for CID :- %d", cid);
573         (void) sprintf(cmd_str, "AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid, pdp_type_str, apn, d_comp, h_comp);
574
575         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
576                                                                    on_response_define_pdp_context, ps_context);
577         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
578                 return TCORE_RETURN_SUCCESS;
579         }
580         _unable_to_get_pending(co_ps, ps_context);
581         return TCORE_RETURN_FAILURE;
582 }
583
584
585 static struct tcore_ps_operations ps_ops = {
586         .define_context = define_ps_context,
587         .activate_context = activate_ps_context,
588         /* Use AT_standard entry point */
589         .deactivate_context = NULL
590 };
591
592 gboolean s_ps_init(TcorePlugin *cp, CoreObject *co_ps)
593 {
594         TcorePlugin *plugin = tcore_object_ref_plugin(co_ps);
595
596         dbg("Enter");
597
598         tcore_ps_override_ops(co_ps, &ps_ops);
599
600         /*
601          * AT_standard handles standard CGEV notifications:
602          * tcore_object_override_callback(co, "+CGEV", on_cgev_notification, NULL);
603          * no need to handle it here.
604          */
605
606         tcore_object_override_callback(co_ps, "+XNOTIFYDUNSTATUS", on_event_dun_call_notification, plugin);
607
608         dbg("Exit");
609
610         return TRUE;
611 }
612
613 void s_ps_exit(TcorePlugin *cp, CoreObject *co_ps)
614 {
615         dbg("Exit");
616 }