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