2 * tel-plugin-at_standard
4 * Copyright (c) 2012 Intel Corporation. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
29 #include <core_object.h>
35 #include <co_context.h>
39 enum pdp_context_state {
44 static TReturn set_pdp_context(CoreObject *co_ps, CoreObject *ps_context,
45 enum pdp_context_state state);
47 static void on_confirmation_ps_message_send(TcorePending *p, gboolean result,
50 dbg("msg out from queue");
52 dbg("Sending %s", (result == TRUE) ? "OK" : "FAIL");
55 static void notify_context_status_changed(CoreObject *co_ps, unsigned int cid,
56 enum ps_data_call_status status)
58 struct tnoti_ps_call_status data_resp = {0};
59 TcorePlugin *p = tcore_object_ref_plugin(co_ps);
60 Server *server = tcore_plugin_ref_server(p);
64 data_resp.context_id = cid;
65 data_resp.state = status;
67 tcore_server_send_notification(server, co_ps, TNOTI_PS_CALL_STATUS,
68 sizeof(struct tnoti_ps_call_status),
74 static void on_unmount_netif(CoreObject *co_ps, const char *netif_name,
77 CoreObject *ps_context = user_data;
82 ifname = tcore_context_get_ipv4_devname(ps_context);
84 if (tcore_util_netif(ifname, FALSE) != TCORE_RETURN_SUCCESS)
85 dbg("disabling network interface failed");
90 static void on_response_set_pdp_context_deactivate(TcorePending *p,
95 CoreObject *co_ps = tcore_pending_ref_core_object(p);
96 TcoreHal *h = tcore_object_get_hal(co_ps);
97 const TcoreATResponse *resp = data;
98 CoreObject *ps_context = user_data;
99 unsigned int cid = tcore_context_get_id(ps_context);
104 * AT+CGACT = 0 is returning NO CARRIER or an error. Just test if the
105 * response contains NO CARRIER else decode CME error.
107 if (resp->lines != NULL) {
110 line = (const char *)resp->lines->data;
111 if (g_strcmp0(line, "NO CARRIER") != 0) {
112 /* TODO: Decode CME error */
114 err("Context %d has not been deactivated", cid);
121 notify_context_status_changed(co_ps, cid, PS_DATA_CALL_NOT_CONNECTED);
123 if (tcore_hal_setup_netif(h, co_ps, on_unmount_netif, ps_context, cid,
124 FALSE) != TCORE_RETURN_SUCCESS)
125 err("Failed to disable network interface");
131 static void on_mount_netif(CoreObject *co_ps, const char *netif_name,
134 CoreObject *ps_context = user_data;
135 struct tnoti_ps_call_status data_status = {0};
140 dbg("devname = [%s]", netif_name);
142 tcore_context_set_ipv4_devname(ps_context, netif_name);
143 if (tcore_util_netif(netif_name, TRUE) != TCORE_RETURN_SUCCESS)
144 dbg("disabling network interface failed");
146 server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
148 data_status.context_id = tcore_context_get_id(ps_context);
149 data_status.state = PS_DATA_CALL_CONNECTED;
151 tcore_server_send_notification(server, co_ps,
152 TNOTI_PS_CALL_STATUS,
153 sizeof(struct tnoti_ps_call_status),
159 static void on_response_get_pdp_address(TcorePending *p, int data_len,
160 const void *data, void *user_data)
162 CoreObject *co_ps = tcore_pending_ref_core_object(p);
163 CoreObject *ps_context = user_data;
164 TcoreHal *h = tcore_object_get_hal(co_ps);
165 GSList *tokens = NULL;
166 const TcoreATResponse *resp = data;
169 char *real_pdp_address;
170 int cid = tcore_context_get_id(ps_context);
174 if (resp->final_response == NULL) {
181 if (resp->lines == NULL) {
182 err("Invalid response line");
186 line = (const char *)resp->lines->data;
187 tokens = tcore_at_tok_new(line);
188 if (g_slist_length(tokens) < 2) {
189 err("Invalid message");
193 dbg("Line: %s", line);
195 /* Skip CID & read directly IP address */
196 pdp_address = g_slist_nth_data(tokens, 1);
197 real_pdp_address = tcore_at_tok_extract(pdp_address);
199 tcore_context_set_ipv4_addr(ps_context, real_pdp_address);
201 dbg("PDP address: %s", real_pdp_address);
203 g_free(real_pdp_address);
205 dbg("Adding default DNS");
207 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
209 if (tcore_hal_setup_netif(h, co_ps, on_mount_netif, ps_context, cid,
210 TRUE) == TCORE_RETURN_SUCCESS)
214 err("Failed to get PDP address deactivating context...");
215 set_pdp_context(co_ps, ps_context, DEACTIVATE);
218 tcore_at_tok_free(tokens);
222 static void get_pdp_address(CoreObject *co_ps, CoreObject *ps_context)
225 unsigned int cid = tcore_context_get_id(ps_context);
229 cmd_str = g_strdup_printf("AT+CGPADDR=%d", cid);
231 if (tcore_prepare_and_send_at_request(co_ps, cmd_str, NULL,
232 TCORE_AT_NO_RESULT, NULL,
233 on_response_get_pdp_address,
235 on_confirmation_ps_message_send, NULL)
236 != TCORE_RETURN_SUCCESS) {
237 err("Failed to prepare and send AT request");
238 set_pdp_context(co_ps, ps_context, DEACTIVATE);
246 static void on_response_set_pdp_context_activate(TcorePending *p, int data_len,
250 CoreObject *co_ps = tcore_pending_ref_core_object(p);
251 const TcoreATResponse *resp = data;
252 CoreObject *ps_context = user_data;
258 get_pdp_address(co_ps, ps_context);
260 unsigned int cid = tcore_context_get_id(ps_context);
262 /* TODO: Manage CME errors */
264 notify_context_status_changed(co_ps, cid, PS_DATA_CALL_NOT_CONNECTED);
270 static TReturn set_pdp_context(CoreObject *co_ps, CoreObject *ps_context,
271 enum pdp_context_state state)
274 unsigned int cid = tcore_context_get_id(ps_context);
275 int ret = TCORE_RETURN_SUCCESS;
276 TcorePendingResponseCallback cb = NULL;
277 gboolean activate = (state == ACTIVATE);
281 dbg("CID %d %s", cid, activate ? "activation" : "deactivation");
283 if (activate == TRUE)
284 cb = on_response_set_pdp_context_activate;
286 cb = on_response_set_pdp_context_deactivate;
288 cmd_str = g_strdup_printf("AT+CGACT=%d,%d", activate ? 1 : 0, cid);
290 if (tcore_prepare_and_send_at_request(co_ps, cmd_str, NULL,
291 TCORE_AT_NO_RESULT, NULL,
293 on_confirmation_ps_message_send, NULL)
294 != TCORE_RETURN_SUCCESS) {
295 err("Failed to prepare and send AT request");
296 notify_context_status_changed(co_ps, cid, PS_DATA_CALL_NOT_CONNECTED);
297 ret = TCORE_RETURN_FAILURE;
307 static void on_response_define_pdp_context(TcorePending *p, int data_len,
311 const TcoreATResponse *resp = data;
312 CoreObject *ps_context = user_data;
313 unsigned int cid = tcore_context_get_id(ps_context);
314 CoreObject *co_ps = tcore_pending_ref_core_object(p);
320 notify_context_status_changed(co_ps, cid, PS_DATA_CALL_CTX_DEFINED);
323 notify_context_status_changed(co_ps, cid, PS_DATA_CALL_NOT_CONNECTED);
329 static TReturn define_pdp_context(CoreObject *co_ps, CoreObject *ps_context,
333 char *cmd_str = NULL;
334 char *pdp_type_str = NULL;
336 enum co_context_type pdp_type;
337 enum co_context_d_comp d_comp;
338 enum co_context_h_comp h_comp;
339 int ret = TCORE_RETURN_FAILURE;
343 pdp_type = tcore_context_get_type(ps_context);
344 cid = tcore_context_get_id(ps_context);
347 case CONTEXT_TYPE_X25:
348 dbg("CONTEXT_TYPE_X25");
349 pdp_type_str = g_strdup("X.25");
352 case CONTEXT_TYPE_IP:
353 dbg("CONTEXT_TYPE_IP");
354 pdp_type_str = g_strdup("IP");
357 case CONTEXT_TYPE_PPP:
358 dbg("CONTEXT_TYPE_PPP");
359 pdp_type_str = g_strdup("PPP");
362 case CONTEXT_TYPE_IPV6:
363 dbg("CONTEXT_TYPE_IPV6");
364 pdp_type_str = g_strdup("IPV6");
368 /* PDP Type not supported supported */
369 err("Unsupported PDP type %d ", pdp_type);
374 d_comp = tcore_context_get_data_compression(ps_context);
375 h_comp = tcore_context_get_header_compression(ps_context);
376 apn = tcore_context_get_apn(ps_context);
378 cmd_str = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid,
379 pdp_type_str, apn, d_comp, h_comp);
381 ret = tcore_prepare_and_send_at_request(co_ps, cmd_str, NULL,
382 TCORE_AT_NO_RESULT, NULL,
383 on_response_define_pdp_context,
385 on_confirmation_ps_message_send, NULL);
387 g_free(pdp_type_str);
391 if (ret == TCORE_RETURN_SUCCESS)
394 err("Failed to prepare and send AT request");
397 notify_context_status_changed(co_ps, cid, PS_DATA_CALL_NOT_CONNECTED);
406 static gboolean on_cgev_notification(CoreObject *co_ps, const void *data,
409 GSList *tokens = NULL;
410 GSList *lines = (GSList *)data;
411 const char *line = lines->data;
420 dbg("Lines->data :%s", line);
422 tokens = tcore_at_tok_new(line);
423 if (g_slist_length(tokens) != 3)
426 noti_data = g_slist_nth_data(tokens, 0);
428 /* Only care about NW context deactivation */
429 if (g_str_has_prefix(noti_data, "NW DEACT") == FALSE)
432 noti_data = g_slist_nth_data(tokens, 1);
433 dbg("PDP Address: %s", noti_data);
435 noti_data = g_slist_nth_data(tokens, 2);
436 cid = (unsigned int)atoi(noti_data);
437 dbg("Context %d deactivated", cid);
439 notify_context_status_changed(co_ps, cid, PS_DATA_CALL_NOT_CONNECTED);
442 * TODO Implement core object PS API to retreive context by ID to get
443 * network interface name and disable it.
447 tcore_at_tok_free(tokens);
454 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context,
457 return set_pdp_context(co_ps, ps_context, ACTIVATE);
460 static TReturn deactivate_ps_context(CoreObject *co_ps, CoreObject *ps_context,
463 return set_pdp_context(co_ps, ps_context, DEACTIVATE);
466 static struct tcore_ps_operations ps_ops = {
467 .define_context = define_pdp_context,
468 .activate_context = activate_ps_context,
469 .deactivate_context = deactivate_ps_context
472 gboolean at_ps_init(TcorePlugin *cp)
474 CoreObject *co = NULL;
477 co = tcore_ps_new(cp, &ps_ops, NULL);
481 tcore_object_add_callback(co, "+CGEV", on_cgev_notification, NULL);
483 server = tcore_plugin_ref_server(cp);
484 tcore_server_add_template_object(server, co);
489 void at_ps_exit(TcorePlugin *cp)
496 co = tcore_plugin_ref_core_object(cp, CORE_OBJECT_TYPE_PS);
500 tcore_object_free(co);