at_ps: Implement activate_context
[platform/core/telephony/tel-plugin-at_standard.git] / src / at_ps.c
1 /*
2  * tel-plugin-at_standard
3  *
4  * Copyright (c) 2012 Intel Corporation. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include <glib.h>
25
26 #include <tcore.h>
27 #include <server.h>
28 #include <plugin.h>
29 #include <core_object.h>
30 #include <hal.h>
31 #include <at.h>
32 #include <util.h>
33
34 #include <co_ps.h>
35 #include <co_context.h>
36
37 #include "at_ps.h"
38
39 enum pdp_context_state {
40         DEACTIVATE      = 0,
41         ACTIVATE        = 1,
42 };
43
44 static TReturn set_pdp_context(CoreObject *co_ps, CoreObject *ps_context,
45                                         enum pdp_context_state state);
46
47 static void on_confirmation_ps_message_send(TcorePending *p, gboolean result,
48                                                 void *user_data)
49 {
50         dbg("msg out from queue");
51
52         dbg("Sending %s", (result == TRUE) ? "OK" : "FAIL");
53 }
54
55 static void notify_context_deactivated(CoreObject *co_ps,
56                                         CoreObject *ps_context)
57 {
58         struct tnoti_ps_call_status data_resp = {0};
59         unsigned int cid = tcore_context_get_id(ps_context);
60         Server *server;
61
62         dbg("Enter");
63
64         data_resp.context_id = cid;
65         data_resp.state = TELEPHONY_GPRS_DATA_STATUS_NOCARRIER;
66         data_resp.result = 0;
67
68         server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
69
70         tcore_server_send_notification(server, co_ps, TNOTI_PS_CALL_STATUS,
71                                         sizeof(struct tnoti_ps_call_status),
72                                         &data_resp);
73
74         dbg("Exit");
75 }
76
77 static void on_setup_netif(CoreObject *co_ps, const char *netif_name,
78                                 void *user_data)
79 {
80         CoreObject *ps_context = user_data;
81         struct tnoti_ps_call_status data_status = {0};
82         Server *server;
83
84         dbg("Enter");
85
86         dbg("devname = [%s]", netif_name);
87
88         if (tcore_util_netif_up(netif_name) != TCORE_RETURN_SUCCESS) {
89                 err("util_netif_up() failed.");
90                 set_pdp_context(co_ps, ps_context, DEACTIVATE);
91                 return;
92         }
93
94         tcore_context_set_ipv4_devname(ps_context, netif_name);
95
96         server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
97
98         data_status.context_id = tcore_context_get_id(ps_context);
99         data_status.state = TELEPHONY_GPRS_DATA_STATUS_CONNECTED;
100         data_status.result = 0;
101
102         tcore_server_send_notification(server, co_ps,
103                                         TNOTI_PS_CALL_STATUS,
104                                         sizeof(struct tnoti_ps_call_status),
105                                         &data_status);
106
107         dbg("Exit");
108 }
109
110 static void on_response_get_pdp_address(TcorePending *p, int data_len,
111                                         const void *data, void *user_data)
112 {
113         CoreObject *co_ps = tcore_pending_ref_core_object(p);
114         CoreObject *ps_context = user_data;
115         TcoreHal *h = tcore_object_get_hal(co_ps);
116         GSList *tokens = NULL;
117         const TcoreATResponse *resp = data;
118         const char *line;
119         char *pdp_address;
120         char *real_pdp_address;
121         int cid = tcore_context_get_id(ps_context);
122
123         dbg("Enter");
124
125         if (NULL == resp->final_response) {
126                 err("Response NOK");
127                 goto error;
128         }
129
130         dbg("Response OK");
131
132         if (NULL == resp->lines) {
133                 err("Invalid response line");
134                 goto error;
135         }
136
137         line = (const char *)resp->lines->data;
138         tokens = tcore_at_tok_new(line);
139         if (g_slist_length(tokens) < 2) {
140                 err("Invalid message");
141                 goto error;
142         }
143
144         dbg("Line: %s", line);
145
146         /* Skip CID & read directly IP address */
147         pdp_address = g_slist_nth_data(tokens, 1);
148         real_pdp_address = tcore_at_tok_extract(pdp_address);
149
150         tcore_context_set_ipv4_addr(ps_context, real_pdp_address);
151
152         dbg("PDP address: %s", real_pdp_address);
153
154         g_free(real_pdp_address);
155
156         dbg("Adding default DNS");
157
158         tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
159
160         if (tcore_hal_setup_netif(h, co_ps, on_setup_netif, ps_context, cid)
161                                         == TCORE_RETURN_SUCCESS)
162                 goto out;
163
164 error:
165         err("Failed to get PDP address deactivating context...");
166         set_pdp_context(co_ps, ps_context, DEACTIVATE);
167
168 out:
169         if (tokens != NULL)
170                 tcore_at_tok_free(tokens);
171
172         dbg("Exit");
173 }
174
175 static void get_pdp_address(CoreObject *co_ps, CoreObject *ps_context)
176 {
177         char *cmd_str = NULL;
178         unsigned int cid = tcore_context_get_id(ps_context);
179
180         dbg("Enter");
181
182         cmd_str = g_strdup_printf("AT+CGPADDR=%d", cid);
183
184         if (tcore_prepare_and_send_at_request(co_ps, cmd_str, NULL,
185                                         TCORE_AT_NO_RESULT, NULL,
186                                         on_response_get_pdp_address,
187                                         ps_context,
188                                         on_confirmation_ps_message_send, NULL)
189                                         != TCORE_RETURN_SUCCESS) {
190                 err("Failed to prepare and send AT request");
191                 set_pdp_context(co_ps, ps_context, DEACTIVATE);
192         }
193
194         g_free(cmd_str);
195
196         dbg("Exit");
197 }
198
199 static void on_response_set_pdp_context_activate(TcorePending *p, int data_len,
200                                                         const void *data,
201                                                         void *user_data)
202 {
203         CoreObject *co_ps = tcore_pending_ref_core_object(p);
204         const TcoreATResponse *resp = data;
205         CoreObject *ps_context = user_data;
206
207         dbg("Enter");
208
209         if (resp->success) {
210                 dbg("Response OK");
211                 get_pdp_address(co_ps, ps_context);
212         } else {
213                 /* TODO: Manage CME errors */
214                 err("Response NOK");
215                 notify_context_deactivated(co_ps, ps_context);
216         }
217
218         dbg("Exit");
219 }
220
221 static TReturn set_pdp_context(CoreObject *co_ps, CoreObject *ps_context,
222                                         enum pdp_context_state state)
223 {
224         char *cmd_str = NULL;
225         unsigned int cid = tcore_context_get_id(ps_context);
226         int ret = TCORE_RETURN_SUCCESS;
227         TcorePendingResponseCallback cb = NULL;
228         gboolean activate = (state == ACTIVATE);
229
230         dbg("Enter");
231
232         dbg("CID %d %s", cid, activate ? "activation" : "deactivation");
233
234         if (activate == TRUE)
235                 cb = on_response_set_pdp_context_activate;
236         else
237                 return TCORE_RETURN_ENOSYS;
238
239         cmd_str = g_strdup_printf("AT+CGACT=%d,%d", activate ? 1 : 0, cid);
240
241         if (tcore_prepare_and_send_at_request(co_ps, cmd_str, NULL,
242                                         TCORE_AT_NO_RESULT, NULL,
243                                         cb, ps_context,
244                                         on_confirmation_ps_message_send, NULL)
245                                         != TCORE_RETURN_SUCCESS) {
246                 err("Failed to prepare and send AT request");
247                 notify_context_deactivated(co_ps, ps_context);
248                 ret =  TCORE_RETURN_FAILURE;
249         }
250
251         g_free(cmd_str);
252
253         dbg("Exit");
254
255         return ret;
256 }
257
258 static void on_response_define_pdp_context(TcorePending *p, int data_len,
259                                                 const void *data,
260                                                 void *user_data)
261 {
262         const TcoreATResponse *resp = data;
263         CoreObject *ps_context = user_data;
264         CoreObject *co_ps = tcore_pending_ref_core_object(p);
265
266         dbg("Enter");
267
268         if (resp->success) {
269                 dbg("Response OK");
270                 set_pdp_context(co_ps, ps_context, ACTIVATE);
271         } else {
272                 err("Response NOK");
273                 notify_context_deactivated(co_ps, ps_context);
274         }
275
276         dbg("Exit");
277 }
278
279 static TReturn define_pdp_context(CoreObject *co_ps, CoreObject *ps_context)
280 {
281         char *apn = NULL;
282         char *cmd_str = NULL;
283         char *pdp_type_str = NULL;
284         unsigned int cid;
285         enum co_context_type pdp_type;
286         enum co_context_d_comp d_comp;
287         enum co_context_h_comp h_comp;
288         int ret = TCORE_RETURN_FAILURE;
289
290         dbg("Enter");
291
292         pdp_type = tcore_context_get_type(ps_context);
293         cid = tcore_context_get_id(ps_context);
294
295         switch (pdp_type) {
296         case CONTEXT_TYPE_X25:
297                 dbg("CONTEXT_TYPE_X25");
298                 pdp_type_str = g_strdup("X.25");
299                 break;
300
301         case CONTEXT_TYPE_IP:
302                 dbg("CONTEXT_TYPE_IP");
303                 pdp_type_str = g_strdup("IP");
304                 break;
305
306         case CONTEXT_TYPE_PPP:
307                 dbg("CONTEXT_TYPE_PPP");
308                 pdp_type_str = g_strdup("PPP");
309                 break;
310
311         case CONTEXT_TYPE_IPV6:
312                 dbg("CONTEXT_TYPE_IPV6");
313                 pdp_type_str = g_strdup("IPV6");
314                 break;
315
316         default:
317                 /* PDP Type not supported supported */
318                 err("Unsupported PDP type %d ", pdp_type);
319
320                 goto error;
321         }
322
323         d_comp = tcore_context_get_data_compression(ps_context);
324         h_comp = tcore_context_get_header_compression(ps_context);
325         apn = tcore_context_get_apn(ps_context);
326
327         cmd_str = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid,
328                                         pdp_type_str, apn, d_comp, h_comp);
329
330         ret = tcore_prepare_and_send_at_request(co_ps, cmd_str, NULL,
331                                         TCORE_AT_NO_RESULT, NULL,
332                                         on_response_define_pdp_context,
333                                         ps_context,
334                                         on_confirmation_ps_message_send, NULL);
335
336         g_free(pdp_type_str);
337         g_free(cmd_str);
338         g_free(apn);
339
340         if (ret == TCORE_RETURN_SUCCESS)
341                 goto out;
342
343         err("Failed to prepare and send AT request");
344
345 error:
346         notify_context_deactivated(co_ps, ps_context);
347
348 out:
349
350         dbg("Exit");
351
352         return ret;
353 }
354
355 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context,
356                                         void *user_data)
357 {
358         return define_pdp_context(co_ps, ps_context);
359 }
360
361 static TReturn deactivate_ps_context(CoreObject *co_ps, CoreObject *ps_context,
362                                         void *user_data)
363 {
364         return TCORE_RETURN_ENOSYS;
365 }
366
367 static struct tcore_ps_operations ps_ops = {
368         .activate_context = activate_ps_context,
369         .deactivate_context = deactivate_ps_context
370 };
371
372 gboolean at_ps_init(TcorePlugin *p)
373 {
374         CoreObject *co_ps;
375
376         co_ps = tcore_ps_new(p, "umts_ps", &ps_ops, NULL);
377         if (NULL == co_ps)
378                 return FALSE;
379
380         return TRUE;
381 }
382
383 void at_ps_exit(TcorePlugin *p)
384 {
385         CoreObject *co_ps;
386
387         co_ps = tcore_plugin_ref_core_object(p, "umts_ps");
388         if (NULL == co_ps)
389                 return;
390
391         tcore_ps_free(co_ps);
392 }