Fix build error for toolchain upgrade
[platform/core/telephony/tel-plugin-atmodem.git] / src / s_ps.c
1 /**
2  * tel-plugin-atmodem
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Kyoungyoup Park <gynaru.park@samsung.com>
7  *          Hayoon Ko       <hayoon.ko@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <glib.h>
28 #include <arpa/inet.h>
29
30 #include <fcntl.h>
31
32 #include <tcore.h>
33 #include <hal.h>
34 #include <core_object.h>
35 #include <plugin.h>
36 #include <queue.h>
37 #include <co_ps.h>
38 #include <co_context.h>
39 #include <user_request.h>
40 #include <server.h>
41 #include <util.h>
42 #include <type/ps.h>
43 #include <at.h>
44
45 #include "s_common.h"
46 #include "s_ps.h"
47
48 static void __notify_context_status_changed(CoreObject *co_ps, guchar context_id, gint status)
49 {
50         Server *server;
51         struct tnoti_ps_call_status ps_call_status;
52
53         dbg("Entry");
54
55         ps_call_status.context_id = (guint)context_id;
56         ps_call_status.state = status;
57         ps_call_status.result = TCORE_RETURN_SUCCESS;
58
59         dbg("Sending PS Call Status Notification - Context ID: [%d] Context State: [%d]",
60                                         ps_call_status.context_id, ps_call_status.state);
61
62         /* Send PS CALL Status Notification */
63         server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
64         tcore_server_send_notification(server, co_ps,
65                         TNOTI_PS_CALL_STATUS,
66                         sizeof(struct tnoti_ps_call_status),
67                         &ps_call_status);
68
69         dbg("Exit");
70 }
71
72 static void on_response_undefine_context_cmd(TcorePending *p,
73         int data_len, const void *data, void *user_data)
74 {
75         const TcoreATResponse *resp = data;
76
77         dbg("Entered");
78
79         if (resp && resp->success) {
80                 dbg("Response Ok");
81                 return;
82         }
83         dbg("Response NOk");
84 }
85
86 static void __send_undefine_context_cmd(CoreObject *co_ps, CoreObject *ps_context)
87 {
88         char *at_cmd;
89         int context_id = 0;
90         TReturn ret;
91
92         dbg("Entered");
93
94         /*Getting Context ID from Core Object*/
95         context_id = tcore_context_get_id(ps_context);
96
97         at_cmd = g_strdup_printf("AT+CGDCONT=0,%d", context_id);
98
99         /* Send Request to modem */
100         ret = tcore_prepare_and_send_at_request(co_ps,
101                 at_cmd, NULL,
102                 TCORE_AT_NO_RESULT,
103                 NULL,
104                 on_response_undefine_context_cmd, NULL,
105                 on_send_at_request, NULL,
106                 0, NULL, NULL);
107         dbg("ret: [0x%x]", ret);
108
109         /* Free resource */
110         g_free(at_cmd);
111
112         return;
113 }
114
115 static void __ps_setup_pdp(CoreObject *co_ps, gint result,
116         const gchar *netif_name, void *user_data)
117 {
118         CoreObject *ps_context = user_data;
119         guchar context_id;
120
121         CHECK_AND_RETURN(ps_context != NULL);
122
123         dbg("Enter");
124
125         if (result < 0) {
126                 err("Failed to setup PDP");
127
128                 /* Deactivate PDP context */
129                 __send_undefine_context_cmd(co_ps, ps_context);
130
131                 return;
132         }
133
134         dbg("devname = [%s]", netif_name);
135
136         context_id = tcore_context_get_id(ps_context);
137         dbg("Context ID : %d", context_id);
138
139         __notify_context_status_changed(co_ps, context_id, 1);
140
141         dbg("Exit");
142 }
143
144 static void __on_response_get_ipconfiguration(TcorePending *p,
145         int data_len, const void *data, void *user_data)
146 {
147         CoreObject *co_ps = tcore_pending_ref_core_object(p);
148         CoreObject *ps_context = user_data;
149         const TcoreATResponse *at_resp = data;
150         guchar context_id;
151         GSList *p_cur = NULL;
152
153         context_id = tcore_context_get_id(ps_context);
154         dbg("Context ID : %d", context_id);
155
156         if (at_resp && at_resp->success) {
157                 for (p_cur = at_resp->lines; p_cur != NULL; p_cur = p_cur->next) {
158                         const gchar *line;
159                         GSList *tokens = NULL;
160
161                         line = (const char *) p_cur->data;
162                         tokens = tcore_at_tok_new(line);
163
164                         if (g_slist_length(tokens) >= 2) {
165                                 gchar *pdp_type = NULL, *apn = NULL;
166                                 gchar *ip = NULL, *pdp_address = NULL, *p_cid = NULL;
167
168                                 p_cid = g_slist_nth_data(tokens, 0);
169                                 dbg("cid: %d", p_cid);
170
171                                 /* Send IP Configuration noti only on the requested CID. */
172                                 if (atoi(p_cid) && (context_id == (unsigned int)atoi(p_cid))) {
173                                         TcoreHal *hal = tcore_object_get_hal(co_ps);
174
175                                         pdp_type = g_slist_nth_data(tokens, 1);
176                                         dbg("PDP type: %s", pdp_type);
177
178                                         if (pdp_type != NULL)   {
179                                                 apn = g_slist_nth_data(tokens, 2);
180                                                 dbg("APN: %s", apn);
181                                         }
182                                         if (apn != NULL) {
183                                                 ip = g_slist_nth_data(tokens, 3);
184                                                 pdp_address = tcore_at_tok_extract(ip);
185                                                 dbg("IP address: %s", ip);
186                                         }
187
188                                         (void)tcore_context_set_address(ps_context, (const char *)pdp_address);
189                                         g_free(pdp_address);
190
191                                         dbg("Adding default DNS pri: 8.8.8.8 sec: 8.8.4.4");
192
193                                         tcore_context_set_dns1(ps_context, "8.8.8.8");
194                                         tcore_context_set_dns2(ps_context, "8.8.4.4");
195
196                                         /* Mount network interface */
197                                         if (tcore_hal_setup_netif(hal, co_ps, __ps_setup_pdp, ps_context, context_id, TRUE)
198                                                         != TCORE_RETURN_SUCCESS) {
199                                                 err("Setup network interface failed");
200                                                 return;
201                                         }
202                                 } else {
203                                         err("No matched response with CID: %d", atoi(p_cid));
204                                 }
205                         }
206                 }
207         } else {
208                 err("Response NOK");
209
210                 context_id = tcore_context_get_id(ps_context);
211                 dbg("Context ID : %d", context_id);
212
213                 __notify_context_status_changed(co_ps, context_id, 3);
214         }
215 }
216
217 static void __get_ipconfiguration(CoreObject *co_ps, CoreObject *ps_context)
218 {
219         TReturn ret;
220
221         dbg("Enter");
222
223         /* Send Request to modem */
224         ret = tcore_prepare_and_send_at_request(co_ps,
225                 "AT+CGDCONT?", NULL,
226                 TCORE_AT_NO_RESULT,
227                 NULL,
228                 __on_response_get_ipconfiguration,
229                 ps_context,
230                 on_send_at_request, NULL,
231                 0, NULL, NULL);
232         if (ret != TCORE_RETURN_SUCCESS) {
233                 err("Failed to prepare and send AT request");
234
235                 /* Deactivate PDP context */
236                 __send_undefine_context_cmd(co_ps, ps_context);
237         }
238
239         dbg("Exit");
240 }
241
242 static void __on_response_attach_ps(TcorePending *p,
243         int data_len, const void *data, void *user_data)
244 {
245         CoreObject *co_ps = tcore_pending_ref_core_object(p);
246         CoreObject *ps_context = user_data;
247         const TcoreATResponse *at_resp = data;
248         guchar context_id;
249
250         CHECK_AND_RETURN(at_resp != NULL);
251         CHECK_AND_RETURN(ps_context != NULL);
252
253         if (at_resp && at_resp->success) {
254                 __get_ipconfiguration(co_ps, ps_context);
255                 return;
256         }
257
258         err("Response NOK");
259
260         context_id = tcore_context_get_id(ps_context);
261         dbg("Context ID : %d", context_id);
262
263         __notify_context_status_changed(co_ps, context_id, 3);
264
265         dbg("Exit");
266 }
267
268 static void __attach_ps(CoreObject *co_ps, CoreObject *ps_context)
269 {
270         TReturn ret;
271
272         dbg("Enter");
273
274         /* Send Request to modem */
275         ret = tcore_prepare_and_send_at_request(co_ps,
276                 "ATD*99***1#", NULL,
277                 TCORE_AT_NO_RESULT,
278                 NULL,
279                 __on_response_attach_ps, ps_context,
280                 on_send_at_request, NULL,
281                 0, NULL, NULL);
282         if (ret != TCORE_RETURN_SUCCESS) {
283                 err("Failed to prepare and send AT request");
284
285                 /* Deactivate PDP context */
286                 __send_undefine_context_cmd(co_ps, ps_context);
287         }
288
289         dbg("Exit");
290 }
291
292 static void on_response_ps_activate_context(TcorePending *p,
293         gint data_len, const void *data, void *user_data)
294 {
295         CoreObject *co_ps = tcore_pending_ref_core_object(p);
296         const TcoreATResponse *at_resp = data;
297         CoreObject *ps_context = user_data;
298
299         dbg("Enter");
300
301         CHECK_AND_RETURN(at_resp != NULL);
302         CHECK_AND_RETURN(ps_context != NULL);
303
304         if (at_resp && at_resp->success) {
305                 dbg("Response OK");
306                 __attach_ps(co_ps, ps_context);
307         } else {
308                 guchar context_id;
309
310                 err("Response NOK");
311
312                 context_id = tcore_context_get_id(ps_context);
313                 dbg("Context ID : %d", context_id);
314
315                 __notify_context_status_changed(co_ps, context_id, 3);
316         }
317
318         dbg("Exit");
319 }
320
321 static void on_response_ps_deactivate_context(TcorePending *p,
322         gint data_len, const void *data, void *user_data)
323 {
324         CoreObject *co_ps = tcore_pending_ref_core_object(p);
325         TcoreHal *hal = tcore_object_get_hal(co_ps);
326         const TcoreATResponse *at_resp = data;
327         CoreObject *ps_context = user_data;
328         guchar context_id;
329
330         dbg("Enter");
331
332         CHECK_AND_RETURN(at_resp != NULL);
333         CHECK_AND_RETURN(ps_context != NULL);
334
335         context_id = tcore_context_get_id(ps_context);
336         dbg("Context ID : %d", context_id);
337
338         /*
339          * AT+CGACT = 0 is returning NO CARRIER or an error. Just test if the
340          * response contains NO CARRIER else decode CME error.
341          */
342         if (at_resp && at_resp->success) {
343                 const gchar *line;
344
345                 line = (const gchar *)at_resp->lines->data;
346                 if (g_strcmp0(line, "NO CARRIER") != 0) {
347                         err("%s", line);
348                         err("Context %d has not been deactivated", context_id);
349
350                         goto out;
351                 }
352         }
353
354         __notify_context_status_changed(co_ps, context_id, 3);
355
356         if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id, FALSE) != TCORE_RETURN_SUCCESS)
357                 err("Failed to disable network interface");
358
359 out:
360         dbg("Exit");
361 }
362
363 static void on_response_ps_define_context(TcorePending *p,
364         gint data_len, const void *data, void *user_data)
365 {
366         const TcoreATResponse *at_resp = data;
367         CoreObject *ps_context = (CoreObject *) user_data;
368         CoreObject *co_ps = tcore_pending_ref_core_object(p);
369         guchar context_id;
370         gint curr_call_status;
371
372         dbg("entry");
373
374         CHECK_AND_RETURN(at_resp != NULL);
375         CHECK_AND_RETURN(ps_context != NULL);
376
377         if (at_resp && at_resp->success) {
378                 dbg("Response OK");
379                 curr_call_status = 0;
380                 tcore_context_set_state(co_ps, CONTEXT_STATE_ACTIVATED);
381         } else {
382                 err("ERROR[%s]", at_resp->final_response);
383                 curr_call_status = 3;
384         }
385
386         context_id = tcore_context_get_id(ps_context);
387         dbg("Context ID : %d", context_id);
388
389         __notify_context_status_changed(co_ps, context_id, curr_call_status);
390 }
391
392 /*
393  * Operation - PDP Context Activate
394  *
395  * Request -
396  * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
397  *
398  * where,
399  * <state>
400  * indicates the state of PDP context activation
401  *
402  * 1 activated
403  *
404  * <cid>
405  * It is a numeric parameter which specifies a particular PDP context definition
406  *
407  * Response -
408  * Success: (No Result)
409  *      OK
410  * Failure:
411  *      +CME ERROR: <error>
412  */
413 static TReturn activate_ps_context(CoreObject *o, CoreObject *ps_context, void* user_data)
414 {
415         gchar *at_cmd = NULL;
416         TReturn ret;
417         guchar context_id;
418
419         dbg("Entry");
420
421         context_id = tcore_context_get_id(ps_context);
422         dbg("Context ID : %d", context_id);
423
424         at_cmd = g_strdup_printf("AT+CGACT=1,%d", context_id);
425         dbg(" at command : %s", at_cmd);
426
427         /* Send Request to modem */
428         ret = tcore_prepare_and_send_at_request(o,
429                 at_cmd, NULL,
430                 TCORE_AT_NO_RESULT,
431                 NULL,
432                 on_response_ps_activate_context, ps_context,
433                 on_send_at_request, NULL,
434                 0, NULL, NULL);
435         if (ret != TCORE_RETURN_SUCCESS) {
436                 err("AT request failed. Send notification for call status [DISCONNECTED]");
437
438                 __notify_context_status_changed(o, context_id, 3);
439         }
440         g_free(at_cmd);
441         dbg("Exit");
442
443         return ret;
444 }
445
446 /*
447  * Operation - PDP Context Deactivate
448  *
449  * Request -
450  * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
451  *
452  * where,
453  * <state>
454  * indicates the state of PDP context activation
455  *
456  * 0 deactivated
457  *
458  * <cid>
459  * It is a numeric parameter which specifies a particular PDP context definition
460  *
461  * Response -
462  * Success: (No Result)
463  *      OK
464  * Failure:
465  *      +CME ERROR: <error>
466  */
467 static TReturn deactivate_ps_context(CoreObject *o, CoreObject *ps_context, void* user_data)
468 {
469         gchar *at_cmd = NULL;
470         TReturn ret;
471         guchar context_id;
472
473         dbg("Entry");
474
475         context_id = tcore_context_get_id(ps_context);
476         dbg("Context ID : %d", context_id);
477
478         at_cmd = g_strdup_printf("AT+CGACT=0,%d", context_id);
479         dbg(" at command : %s", at_cmd);
480
481         /* Send Request to modem */
482         ret = tcore_prepare_and_send_at_request(o,
483                 at_cmd, NULL,
484                 TCORE_AT_NO_RESULT,
485                 NULL,
486                 on_response_ps_deactivate_context, ps_context,
487                 on_send_at_request, NULL,
488                 0, NULL, NULL);
489         if (ret != TCORE_RETURN_SUCCESS) {
490                 err("AT request failed. Send notification for call status [DISCONNECTED]");
491                 __notify_context_status_changed(o, context_id, 3);
492         }
493         g_free(at_cmd);
494         dbg("Exit");
495
496         return ret;
497 }
498
499 /*
500  * Operation - Define PDP Context
501  *
502  * Request -
503  * AT-Command: AT+CGDCONT= [<cid> [, <PDP_type> [, <APN> [, <PDP_addr> [,
504  * <d_comp> [, <h_comp> [, <pd1> [... [, pdN]]]]]]]]]
505  * where,
506  * <cid>
507  * It is a numeric parameter, which specifies a particular PDP context definition
508  *
509  * <PDP_type>
510  * "IP" Internet Protocol (IETF STD 5)
511  * "IPV6" Internet Protocol, version 6 (IETF RFC 2460)
512  * "IPV4V6" Virtual <PDP_type>introduced to handle dual IP stack UE capability (see 3GPP
513  *  TS 24.301[83])
514  *
515  * <APN>
516  * Access Point Name
517  *
518  * <PDP_address>
519  * It is the string parameter that identifies the MT in the address space applicable to the PDP
520  * The allocated address may be read using the command +CGPADDR command
521  *
522  * <d_comp>
523  * A numeric parameter that controls PDP data compression
524  * 0 off
525  * 1 on
526  * 2 V.42 bis
527  *
528  * <h_comp>
529  * A numeric parameter that controls PDP header compression
530  * 0 off
531  * 1 on
532  * 2 RFC1144
533  * 3 RFC2507
534  * 4 RFC3095
535  *
536  * <pd1>...<pdN>
537  * zero to N string parameters whose meanings are specific to the <PDP_type>
538  *
539  * Response -
540  * Success: (No Result)
541  *      OK
542  * Failure:
543  *      +CME ERROR: <error>
544  */
545 static TReturn define_ps_context(CoreObject *o, CoreObject *ps_context, void *user_data)
546 {
547         guchar context_id = 0;
548         gchar *at_cmd = NULL;
549         gchar *apn = NULL;
550         gchar *pdp_type_str = NULL;
551         gint pdp_type;
552         gint d_comp;
553         gint h_comp;
554         TReturn ret = TCORE_RETURN_FAILURE;
555
556         dbg("Entry");
557
558         context_id = tcore_context_get_id(ps_context);
559         dbg("Context ID : %d", context_id);
560         pdp_type = tcore_context_get_type(ps_context);
561         dbg("PDP Type : %d", pdp_type);
562
563         switch (pdp_type) {
564         case CONTEXT_TYPE_X25:
565                 dbg("CONTEXT_TYPE_X25");
566                 pdp_type_str = g_strdup("X.25");
567         break;
568
569         case CONTEXT_TYPE_IP:
570                 dbg("CONTEXT_TYPE_IP");
571                 pdp_type_str = g_strdup("IP");
572         break;
573
574         case CONTEXT_TYPE_PPP:
575                 dbg("CONTEXT_TYPE_PPP");
576                 pdp_type_str = g_strdup("PPP");
577         break;
578
579         case CONTEXT_TYPE_IPV6:
580                 dbg("CONTEXT_TYPE_IPV6");
581                 pdp_type_str = g_strdup("IPV6");
582         break;
583
584         default:
585                 /*PDP Type not supported*/
586                 dbg("Unsupported PDP type: %d", pdp_type);
587                 goto error;
588         }
589
590         d_comp = tcore_context_get_data_compression(ps_context);
591         h_comp = tcore_context_get_header_compression(ps_context);
592         apn = tcore_context_get_apn(ps_context);
593
594         /* AT-Command */
595         at_cmd = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d",
596                 context_id, pdp_type_str, apn, d_comp, h_comp);
597         dbg("AT-Command : %s", at_cmd);
598
599         /* Send Request to modem */
600         ret = tcore_prepare_and_send_at_request(o,
601                 at_cmd, NULL,
602                 TCORE_AT_NO_RESULT,
603                 NULL,
604                 on_response_ps_define_context, ps_context,
605                 on_send_at_request, NULL,
606                 0, NULL, NULL);
607
608         g_free(pdp_type_str);
609         g_free(at_cmd);
610         g_free(apn);
611
612         if (ret == TCORE_RETURN_SUCCESS)
613                 goto out;
614
615 error:
616         err("Failed to prepare and send AT request");
617         __notify_context_status_changed(o, context_id, 3);
618
619 out:
620         dbg("Exit");
621         return ret;
622 }
623
624 /* PS Operations */
625 static struct tcore_ps_operations ps_ops = {
626         .define_context = define_ps_context,
627         .activate_context = activate_ps_context,
628         .deactivate_context = deactivate_ps_context
629 };
630
631
632 gboolean s_ps_init(TcorePlugin *p, TcoreHal *h)
633 {
634         CoreObject *o;
635
636         dbg("Entry");
637         o = tcore_ps_new(p, "umts_ps", &ps_ops, h);
638         if (!o)
639                 return FALSE;
640
641         dbg("Exit");
642         return TRUE;
643 }
644
645 void s_ps_exit(TcorePlugin *p)
646 {
647         CoreObject *o;
648
649         o = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_PS);
650         CHECK_AND_RETURN(o != NULL);
651
652         tcore_ps_free(o);
653         dbg("Exit");
654 }