Fix typo in plugin
[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_mount_netif(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         if (tcore_util_netif(netif_name, TRUE) != TCORE_RETURN_SUCCESS) {
200                 dbg("disabling network interface failed");
201                 return;
202         }
203
204         server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
205
206         data_status.context_id = tcore_context_get_id(ps_context);
207         data_status.state = PS_DATA_CALL_CONNECTED;
208
209         tcore_server_send_notification(server, co_ps,
210                                         TNOTI_PS_CALL_STATUS,
211                                         sizeof(struct tnoti_ps_call_status),
212                                         &data_status);
213
214         dbg("Exit");
215 }
216
217 static void on_response_get_dns_cmnd(TcorePending *p, int data_len, const void *data, void *user_data)
218 {
219         GSList *tokens = NULL;
220         GSList *pRespData;
221         const char *line = NULL;
222         char *dns_prim = NULL;
223         char *dns_sec = NULL;
224         char *token_dns = NULL;
225         int no_pdp_active = 0;
226         CoreObject *ps_context = user_data;
227         const TcoreATResponse *resp = data;
228         CoreObject *co_ps = tcore_pending_ref_core_object(p);
229         int cid = tcore_context_get_id(ps_context);
230         TcoreHal *h = tcore_object_get_hal(co_ps);
231
232         dbg("Entered");
233
234         if (resp->final_response) {
235                 dbg("Response OK");
236                 if (resp->lines) {
237                         dbg("DNS data present in the Response");
238                         pRespData = (GSList *) resp->lines;
239                         no_pdp_active = g_slist_length(pRespData);
240                         dbg("Total Number of Active PS Context :- %d", no_pdp_active);
241                         if (0 == no_pdp_active) {
242                                 goto exit_fail;
243                         }
244                         while (pRespData) {
245                                 dbg("traversing the DNS data for each active context");
246                                 line = (const char *) pRespData->data;
247                                 dbg("Response->lines->data :%s", line);
248                                 tokens = tcore_at_tok_new(line);
249                                 if (cid == atoi(g_slist_nth_data(tokens, 0))) {
250                                         dbg("Found the DNS details for the Current context");
251                                         dbg("Context Id of The Context : %d", atoi(g_slist_nth_data(tokens, 0)));
252                                         break;
253                                 }
254                                 tcore_at_tok_free(tokens);
255                                 tokens = NULL;
256                                 pRespData = pRespData->next;
257                         }
258                         { /* Read primary DNS */
259                                 token_dns = g_slist_nth_data(tokens, 1);
260                                 /* Strip off starting " and ending " from this token to read actual PDP address */
261                                 dns_prim = util_removeQuotes((void *) token_dns);
262                                 dbg("Token_dns :%s", token_dns);
263                                 dbg("Primary DNS :- %s", dns_prim);
264                         }
265                         { /* Read Secondary DNS */
266                                 token_dns = g_slist_nth_data(tokens, 2);
267                                 dns_sec = util_removeQuotes((void *) token_dns);
268
269                                 dbg("Token_dns :%s", token_dns);
270                                 dbg("Secondary DNS :- %s", dns_sec);
271                         }
272
273                         tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
274                         _ps_free(dns_prim);
275                         _ps_free(dns_sec);
276
277                         tcore_at_tok_free(tokens);
278                         tokens = NULL;
279                         goto exit_success;
280                 } else {
281                         dbg("No data present in the Response");
282                 }
283         }
284         dbg("Response NOK");
285 exit_fail:
286         {
287                 dbg("Adding default DNS");
288
289                 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
290         }
291 exit_success:
292         {
293                 /* mount network interface */
294                 if (tcore_hal_setup_netif(h, co_ps, on_mount_netif, ps_context, cid, TRUE)
295                                 != TCORE_RETURN_SUCCESS) {
296                         err("Setup network interface failed");
297                         return;
298                 }
299
300                 dbg("EXIT : Without error");
301         }
302 }
303
304 static TReturn send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
305 {
306         TcoreHal *hal = NULL;
307         TcorePending *pending = NULL;
308         char cmd_str[MAX_AT_CMD_STR_LEN];
309
310         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
311
312         dbg("Entered");
313         hal = tcore_object_get_hal(co_ps);
314
315         (void) sprintf(cmd_str, "AT+XDNS?");
316         pending = tcore_at_pending_new(co_ps, cmd_str, "+XDNS", TCORE_AT_MULTILINE,
317                                                                    on_response_get_dns_cmnd, ps_context);
318         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
319                 return TCORE_RETURN_SUCCESS;
320         }
321         _unable_to_get_pending(co_ps, ps_context);
322         return TCORE_RETURN_FAILURE;
323 }
324
325 static void on_response_get_pdp_address(TcorePending *p, int data_len, const void *data, void *user_data)
326 {
327         const TcoreATResponse *resp = data;
328         CoreObject *co_ps = tcore_pending_ref_core_object(p);
329         CoreObject *ps_context = user_data;
330         GSList *tokens = NULL;
331         const char *line;
332         char *token_pdp_address;
333         dbg("Enetered");
334         if (resp->final_response) {
335                 dbg("RESPONSE OK");
336                 if (resp->lines != NULL) {
337                         dbg("resp->lines present ");
338                         line = (const char *) resp->lines->data;
339                         tokens = tcore_at_tok_new(line);
340                         if (g_slist_length(tokens) < 2) {
341                                 msg("invalid message");
342                                 goto error;
343                         }
344                         dbg("line:- %s", line);
345                         /* CID is already stored in ps_context, skip over & read PDP address */
346                         token_pdp_address = g_slist_nth_data(tokens, 1);
347
348                         dbg("token_pdp_address :- %s", token_pdp_address);
349                         /* Strip off starting " and ending " from this token to read actual PDP address */
350                         (void) tcore_context_set_ipv4_addr(ps_context, (const char *)token_pdp_address);
351                 }
352
353                 (void) send_get_dns_cmd(co_ps, ps_context);
354         } else {
355                 dbg("Response NOK");
356                 /*without PDP address we will not be able to start packet service*/
357                 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
358         }
359 error:
360         tcore_at_tok_free(tokens);
361         return;
362 }
363
364 static TReturn send_get_pdp_address_cmd(CoreObject *co_ps, CoreObject *ps_context)
365 {
366         TcoreHal *hal = NULL;
367         TcorePending *pending = NULL;
368         unsigned int cid = PS_INVALID_CID;
369         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
370
371         dbg("Entered");
372         hal = tcore_object_get_hal(co_ps);
373
374         cid = tcore_context_get_id(ps_context);
375         (void) sprintf(cmd_str, "AT+CGPADDR=%d", cid);
376         pending = tcore_at_pending_new(co_ps, cmd_str, "+CGPADDR", TCORE_AT_SINGLELINE,
377                                                                    on_response_get_pdp_address, ps_context);
378         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
379                 return TCORE_RETURN_SUCCESS;
380         }
381         _unable_to_get_pending(co_ps, ps_context);
382         return TCORE_RETURN_FAILURE;
383 }
384
385 static void on_response_send_pdp_activate_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
386 {
387         CoreObject *co_ps = NULL;
388         const TcoreATResponse *resp = data;
389         CoreObject *ps_context = user_data;
390
391         int cid;
392         cid = tcore_context_get_id(ps_context);
393
394
395         dbg("Entered");
396         if (!p) {
397                 goto error;
398         }
399         co_ps = tcore_pending_ref_core_object(p);
400
401         if (resp->success) {
402                 dbg("Response Ok");
403                 /*getting the IP address and DNS from the modem*/
404                 dbg("Getting the IP Address");
405                 (void) send_get_pdp_address_cmd(co_ps, ps_context);
406                 return;
407         } else {
408                 dbg("Unable to actiavte PDP context for CID: %d ", cid);
409                 dbg("Undefineing the PDP context");
410                 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
411                 send_undefine_context_cmd(co_ps, ps_context);
412                 return;
413         }
414 error:
415         {
416                 _unable_to_get_pending(co_ps, ps_context);
417                 return;
418         }
419 }
420
421 static TReturn send_pdp_activate_cmd(CoreObject *co_ps, CoreObject *ps_context)
422 {
423         TcoreHal *hal = NULL;
424         TcorePending *pending = NULL;
425         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
426         int cid = 0;
427         dbg("Entered");
428         /* FIXME: Before MUX setup, use PHY HAL directly. */
429         hal = tcore_object_get_hal(co_ps);
430
431         /*Getting Context ID from Core Object*/
432         cid = tcore_context_get_id(ps_context);
433         (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_ACTIVATE, cid);
434         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
435                                                                    on_response_send_pdp_activate_cmd, ps_context);
436         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
437                 return TCORE_RETURN_SUCCESS;
438         }
439         _unable_to_get_pending(co_ps, ps_context);
440         return TCORE_RETURN_FAILURE;
441 }
442
443 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
444 {
445         dbg("Entered");
446         return send_pdp_activate_cmd(co_ps, ps_context);
447 }
448
449 static void on_response_xdns_enable_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
450 {
451         TcoreATResponse *resp = (TcoreATResponse *) data;
452         CoreObject *co_ps = tcore_pending_ref_core_object(p);
453         CoreObject *ps_context = user_data;
454         struct tnoti_ps_call_status noti = {0};
455         int cid = -1;
456         
457         dbg("Entered");
458
459         cid = tcore_context_get_id(ps_context);
460         
461         if (resp->success) {
462                 dbg("Response OK");
463                 dbg("DNS address getting is Enabled");          
464                 noti.context_id = cid;
465                 noti.state = PS_DATA_CALL_CTX_DEFINED;
466         } else {
467                 dbg("Response NOK");            
468                 noti.context_id = cid;
469                 noti.state = PS_DATA_CALL_NOT_CONNECTED;
470                 /*If response to enable the DNS NOK then we will use google DNS for the PDP context*/
471         }
472
473         tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
474                                                                    TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), &noti);
475         return;
476 }
477
478 static TReturn send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
479 {
480         TcoreHal *hal = NULL;
481         TcorePending *pending = NULL;
482         int cid = -1;
483         char cmd_str[MAX_AT_CMD_STR_LEN];
484
485         dbg("Entered");
486         memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
487
488         hal = tcore_object_get_hal(co_ps);
489         cid = tcore_context_get_id(ps_context);
490
491         (void) sprintf(cmd_str, "AT+XDNS=%d,%d", cid, AT_XDNS_ENABLE);
492         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
493                                                                    on_response_xdns_enable_cmd, ps_context);
494         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
495                 return TCORE_RETURN_SUCCESS;
496         }
497         _unable_to_get_pending(co_ps, ps_context);
498         return TCORE_RETURN_FAILURE;
499 }
500
501 static void on_response_define_pdp_context(TcorePending *p, int data_len, const void *data, void *user_data)
502 {
503         const TcoreATResponse *resp = data;
504         CoreObject *ps_context = (CoreObject *) user_data;
505         CoreObject *co_ps = tcore_pending_ref_core_object(p);
506
507         dbg("Entered");
508         if (resp->success) {
509                 dbg("Response OK");
510                 send_xdns_enable_cmd(co_ps, ps_context);
511         } else {
512                 dbg("response NOK");
513                 _unable_to_get_pending(co_ps, ps_context);
514                 dbg("Exiting");
515         }
516         return;
517 }
518
519 static TReturn define_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
520 {
521         TcoreHal *hal = NULL;
522         TcorePending *pending = NULL;
523         char *apn = NULL;
524         char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
525         char pdp_type_str[10] = {0};
526         unsigned int cid = PS_INVALID_CID;
527         enum co_context_type pdp_type;
528         enum co_context_d_comp d_comp;
529         enum co_context_h_comp h_comp;
530
531         dbg("Entered");
532
533         cid = tcore_context_get_id(ps_context);
534         pdp_type = tcore_context_get_type(ps_context);
535         d_comp = tcore_context_get_data_compression(ps_context);
536         h_comp = tcore_context_get_header_compression(ps_context);
537         apn = tcore_context_get_apn(ps_context);
538
539         hal = tcore_object_get_hal(co_ps);
540         switch (pdp_type) {
541         case CONTEXT_TYPE_X25:
542         {
543                 dbg("CONTEXT_TYPE_X25");
544                 strcpy(pdp_type_str, "X.25");
545                 break;
546         }
547
548         case CONTEXT_TYPE_IP:
549         {
550                 dbg("CONTEXT_TYPE_IP");
551                 strcpy(pdp_type_str, "IP");
552         }
553         break;
554
555         case CONTEXT_TYPE_PPP:
556         {
557                 dbg("CONTEXT_TYPE_PPP");
558                 strcpy(pdp_type_str, "PPP");
559         }
560         break;
561
562         case CONTEXT_TYPE_IPV6:
563         {
564                 dbg("CONTEXT_TYPE_IPV6");
565                 strcpy(pdp_type_str, "IPV6");
566                 break;
567         }
568
569         default:
570         {
571                 /*PDP Type not supported supported*/
572                 dbg("Unsupported PDP type :- %d returning ", pdp_type);
573                 return TCORE_RETURN_FAILURE;
574         }
575         }
576         dbg("Activating context for CID :- %d", cid);
577         (void) sprintf(cmd_str, "AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid, pdp_type_str, apn, d_comp, h_comp);
578
579         pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
580                                                                    on_response_define_pdp_context, ps_context);
581         if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
582                 return TCORE_RETURN_SUCCESS;
583         }
584         _unable_to_get_pending(co_ps, ps_context);
585         return TCORE_RETURN_FAILURE;
586 }
587
588
589 static struct tcore_ps_operations ps_ops = {
590         .define_context = define_ps_context,
591         .activate_context = activate_ps_context,
592         /* Use AT_standard entry point */
593         .deactivate_context = NULL
594 };
595
596 gboolean s_ps_init(TcorePlugin *cp, CoreObject *co_ps)
597 {
598         TcorePlugin *plugin = tcore_object_ref_plugin(co_ps);
599
600         dbg("Enter");
601
602         tcore_ps_override_ops(co_ps, &ps_ops);
603
604         /*
605          * AT_standard handles standard CGEV notifications:
606          * tcore_object_override_callback(co, "+CGEV", on_cgev_notification, NULL);
607          * no need to handle it here.
608          */
609
610         tcore_object_override_callback(co_ps, "+XNOTIFYDUNSTATUS", on_event_dun_call_notification, plugin);
611
612         dbg("Exit");
613
614         return TRUE;
615 }
616
617 void s_ps_exit(TcorePlugin *cp, CoreObject *co_ps)
618 {
619         dbg("Exit");
620 }