4 * Copyright (c) 2013 Samsung Electronics Co. Ltd. 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.
28 #include <core_object.h>
35 #include <co_context.h>
38 #include "imc_common.h"
41 TcorePsCallState ps_call_status;
44 static void __notify_context_status_changed(CoreObject *co_ps, guint context_id,
45 TcorePsCallState status)
47 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
48 TcorePsCallStatusInfo data_resp = {0,};
49 tcore_check_return_assert(private_info != NULL);
51 private_info->ps_call_status = status;
52 data_resp.context_id = context_id;
53 data_resp.state = status;
54 dbg("Sending PS Call Status Notification - Context ID: [%d] Context State: [%d]",
55 data_resp.context_id, data_resp.state);
57 /* Send PS CALL Status Notification */
58 (void)tcore_object_send_notification(co_ps,
59 TCORE_NOTIFICATION_PS_CALL_STATUS,
60 sizeof(TcorePsCallStatusInfo),
65 static TcoreHookReturn on_hook_imc_nw_registration_status(TcorePlugin *plugin,
66 TcoreNotification command, guint data_len, void *data, void *user_data)
68 const TelNetworkRegStatusInfo *nw_reg_status = (TelNetworkRegStatusInfo *)data;
69 gboolean state = FALSE;
71 tcore_check_return_value(nw_reg_status != NULL,
72 TCORE_HOOK_RETURN_CONTINUE);
75 dbg("nw_reg_status->ps_status [%d]",nw_reg_status->ps_status);
76 dbg("nw_reg_status->cs_status [%d]",nw_reg_status->cs_status);
78 /* Setting if PS is online or not */
79 if(nw_reg_status->ps_status == TEL_NETWORK_REG_STATUS_REGISTERED ||
80 nw_reg_status->ps_status == TEL_NETWORK_REG_STATUS_ROAMING) {
81 /* Set PS is online */
85 dbg("PS online state [%d]", state);
87 /* Set Online state */
88 tcore_ps_set_online((CoreObject *)user_data, state);
89 return TCORE_HOOK_RETURN_CONTINUE;
93 * Notification - GPRS event reporting
96 * +CGEV: NW DEACT <PDP_type>, <PDP_addr>, [<cid>]
97 * The network has forced a context deactivation. The <cid> that was used to activate the context is provided if
100 static gboolean on_notification_imc_ps_cgev(CoreObject *co_ps,
101 const void *data, void *user_data)
103 GSList *tokens = NULL;
104 GSList *lines = (GSList *)data;
105 const gchar *line = lines->data;
113 err("Ignore, No data present in notification received for CGEV");
117 dbg("Lines->data :%s", line);
119 tokens = tcore_at_tok_new(line);
120 if (g_slist_length(tokens) != 3) {
121 err("Ignore, sufficient data not present for deactivation");
125 noti_data = g_slist_nth_data(tokens, 0);
127 /* Only care about NW context deactivation */
128 if (g_str_has_prefix(noti_data, "NW DEACT") == FALSE) {
129 err("Ignore, only care about nw deactivation");
133 noti_data = g_slist_nth_data(tokens, 1);
134 dbg("PDP Address: %s", noti_data);
136 noti_data = g_slist_nth_data(tokens, 2);
137 /*TODO: Need to handle context id with multiple PDP*/
138 if (noti_data != NULL)
139 context_id = (guint)atoi(noti_data);
141 err("No Context ID!");
145 dbg("Context %d deactivated", context_id);
147 __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED);
149 hal = tcore_object_get_hal(co_ps);
150 if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id,
151 FALSE) != TEL_RETURN_SUCCESS)
152 err("Failed to disable network interface");
154 tcore_at_tok_free(tokens);
158 static void __imc_ps_setup_pdp(CoreObject *co_ps, gint result, const gchar *netif_name,
161 CoreObject *ps_context = user_data;
164 tcore_check_return_assert(ps_context != NULL);
169 err("Result [%d],Hence Deactivating context ", result);
170 /* Deactivate PDP context */
171 (void)tcore_object_dispatch_request(co_ps, TRUE,
172 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
179 dbg("devname = [%s]", netif_name);
181 tcore_context_set_ipv4_devname(ps_context, netif_name);
183 (void)tcore_context_get_id(ps_context, &context_id);
184 dbg("Context ID : %d", context_id);
186 __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_CONNECTED);
191 static void __on_response_imc_ps_send_get_dns_cmd(TcorePending *p, guint data_len, const void *data, void *user_data)
193 const TcoreAtResponse *at_resp = data;
194 CoreObject *ps_context = user_data;
195 CoreObject *co_ps = tcore_pending_ref_core_object(p);
197 GSList *tokens = NULL;
199 const char *line = NULL;
200 char *dns_prim = NULL;
201 char *dns_sec = NULL;
202 char *token_dns = NULL;
203 gint no_pdp_active = 0;
204 TcoreHal *hal = tcore_object_get_hal(co_ps);
208 tcore_check_return_assert(at_resp != NULL);
209 tcore_check_return_assert(ps_context != NULL);
212 (void)tcore_context_get_id(ps_context, &context_id);
213 dbg("Context ID : %d", context_id);
215 if (at_resp && at_resp->success) {
217 if (at_resp->lines) {
218 dbg("DNS data present in the Response");
219 lines = (GSList *) at_resp->lines;
220 no_pdp_active = g_slist_length(lines);
221 dbg("Total Number of Active PS Context: [%d]", no_pdp_active);
222 if (0 == no_pdp_active) {
227 line = (const char *) lines->data;
228 dbg("Received Data: [%s]", line);
229 tokens = tcore_at_tok_new(line);
231 /* Check if Context ID is matching */
232 if (context_id == (guint)(atoi(g_slist_nth_data(tokens, 0)))) {
233 dbg("Found the DNS details for the Current Context - Context ID: [%d]", context_id);
237 tcore_at_tok_free(tokens);
240 /* Move to next line */
244 /* Read primary DNS */
246 token_dns = g_slist_nth_data(tokens, 1);
247 dns_prim = tcore_at_tok_extract(token_dns);
248 dbg("Primary DNS: [%s]", dns_prim);
251 /* Read Secondary DNS */
253 token_dns = g_slist_nth_data(tokens, 2);
254 dns_sec = tcore_at_tok_extract(token_dns);
255 dbg("Secondary DNS: [%s]", dns_sec);
258 if ((g_strcmp0("0.0.0.0", dns_prim) == 0)
259 && (g_strcmp0("0.0.0.0", dns_sec) == 0)) {
262 tcore_free(dns_prim);
265 tcore_at_tok_free(tokens);
271 /* Set DNS Address */
272 tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
273 tcore_free(dns_prim);
276 tcore_at_tok_free(tokens);
280 dbg("No data present in the Response");
286 dbg("Adding default DNS");
287 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
290 /* Mount network interface */
291 if (tcore_hal_setup_netif(hal, co_ps, __imc_ps_setup_pdp, ps_context, context_id, TRUE)
292 != TEL_RETURN_SUCCESS) {
293 err("Setup network interface failed");
298 static void __imc_ps_send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
300 TelReturn ret = TEL_RETURN_FAILURE;
302 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
306 tcore_check_return_assert(private_info != NULL);
308 (void)tcore_context_get_id(ps_context, &context_id);
309 dbg("Context ID : %d", context_id);
311 /* Send Request to modem */
312 ret = tcore_at_prepare_and_send_request(co_ps,
314 TCORE_AT_COMMAND_TYPE_MULTILINE,
316 __on_response_imc_ps_send_get_dns_cmd,
318 on_send_imc_request, NULL);
319 if (ret != TEL_RETURN_SUCCESS){
320 TcorePsCallState curr_call_status;
321 err("Failed to prepare and send AT request");
322 curr_call_status = private_info->ps_call_status;
323 __notify_context_status_changed(co_ps, context_id, curr_call_status);
327 static void __on_response_imc_ps_get_pdp_address(TcorePending *p, guint data_len,
328 const void *data, void *user_data)
330 const TcoreAtResponse *at_resp = data;
331 CoreObject *co_ps = tcore_pending_ref_core_object(p);
332 CoreObject *ps_context = user_data;
333 GSList *tokens = NULL;
336 char *real_pdp_address;
340 tcore_check_return_assert(at_resp != NULL);
341 tcore_check_return_assert(ps_context != NULL);
343 if (at_resp->success != TRUE) {
344 err("Response NOt OK");
350 if (at_resp->lines == NULL) {
351 err("Invalid response line");
355 line = (const char *)at_resp->lines->data;
356 tokens = tcore_at_tok_new(line);
357 if (g_slist_length(tokens) < 2) {
358 err("Invalid message");
362 dbg("Line: %s", line);
364 /* Skip CID & read directly IP address */
365 pdp_address = g_slist_nth_data(tokens, 1);
366 real_pdp_address = tcore_at_tok_extract(pdp_address);
368 tcore_context_set_ipv4_addr(ps_context, real_pdp_address);
370 dbg("PDP address: %s", real_pdp_address);
372 tcore_free(real_pdp_address);
374 /* Get DNS Address */
375 dbg("Getting DNS Address");
376 __imc_ps_send_get_dns_cmd(co_ps, ps_context);
380 err("Failed to get PDP address deactivating context...");
381 /* Deactivate PDP context */
382 (void)tcore_object_dispatch_request(co_ps, TRUE,
383 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
387 tcore_at_tok_free(tokens);
391 static void __imc_ps_get_pdp_address(CoreObject *co_ps, CoreObject *ps_context)
394 gchar *at_cmd = NULL;
399 (void)tcore_context_get_id(ps_context, &context_id);
400 dbg("Context ID : %d", context_id);
403 at_cmd = g_strdup_printf("AT+CGPADDR=%d", context_id);
404 dbg(" at command : %s", at_cmd);
406 /* Send Request to modem */
407 ret = tcore_at_prepare_and_send_request(co_ps,
409 TCORE_AT_COMMAND_TYPE_SINGLELINE,
411 __on_response_imc_ps_get_pdp_address,
413 on_send_imc_request, NULL);
414 if (ret != TEL_RETURN_SUCCESS){
415 err("Failed to prepare and send AT request");
416 /* Deactivate PDP context */
417 (void)tcore_object_dispatch_request(co_ps, TRUE,
418 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
419 &ps_context, sizeof(CoreObject *),
425 static void __on_response_imc_ps_send_xdns_enable_cmd(TcorePending *p,
426 guint data_len, const void *data, void *user_data)
428 const TcoreAtResponse *at_resp = data;
429 CoreObject *co_ps = tcore_pending_ref_core_object(p);
430 CoreObject *ps_context = (CoreObject *) user_data;
432 TcorePsCallState status = TCORE_PS_CALL_STATE_NOT_CONNECTED;
434 tcore_check_return_assert(at_resp != NULL);
435 tcore_check_return_assert(ps_context != NULL);
439 (void)tcore_context_get_id(ps_context, &context_id);
440 dbg("Context ID : %d", context_id);
442 if (at_resp->success) {
443 dbg("Response OK, Dynamic DNS is enabled successfully");
444 status = TCORE_PS_CALL_STATE_CTX_DEFINED;
446 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
447 tcore_check_return_assert(private_info != NULL);
449 status = private_info->ps_call_status;
450 err("ERROR [%s]", at_resp->final_response);
452 /* Send PS CALL Status Notification */
453 __notify_context_status_changed(co_ps, context_id, status);
456 static TelReturn __imc_ps_send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
459 gchar *at_cmd = NULL;
461 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
463 tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
467 (void)tcore_context_get_id(ps_context, &context_id);
468 dbg("Context ID : %d", context_id);
471 at_cmd = g_strdup_printf("AT+XDNS=%d,1", context_id);
472 dbg("AT Command : %s", at_cmd);
474 /* Send Request to modem */
475 ret = tcore_at_prepare_and_send_request(co_ps,
477 TCORE_AT_COMMAND_TYPE_SINGLELINE,
479 __on_response_imc_ps_send_xdns_enable_cmd,
481 on_send_imc_request, NULL);
482 if (ret != TEL_RETURN_SUCCESS){
483 TcorePsCallState curr_call_status;
485 err("Failed to prepare and send AT request");
486 curr_call_status = private_info->ps_call_status;
487 __notify_context_status_changed(co_ps, context_id, curr_call_status);
492 static void on_response_imc_ps_activate_context(TcorePending *p, guint data_len,
496 const TcoreAtResponse *at_resp = data;
497 CoreObject *co_ps = tcore_pending_ref_core_object(p);
498 CoreObject *ps_context = user_data;
499 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
503 tcore_check_return_assert(at_resp != NULL);
504 tcore_check_return_assert(ps_context != NULL);
505 tcore_check_return_assert(private_info != NULL);
507 if (at_resp->success) {
508 dbg("Response OK, Get IP address of data session");
509 __imc_ps_get_pdp_address(co_ps, ps_context);
512 TcorePsCallState curr_call_status;
513 (void)tcore_context_get_id(ps_context, &context_id);
514 err("Response NOT OK,Sending call disconnect notification");
515 curr_call_status = private_info->ps_call_status;
516 __notify_context_status_changed(co_ps, context_id, curr_call_status);
520 static void on_response_imc_ps_deactivate_context(TcorePending *p, guint data_len,
524 const TcoreAtResponse *at_resp = data;
525 CoreObject *co_ps = tcore_pending_ref_core_object(p);
526 CoreObject *ps_context = user_data;
527 TcoreHal *hal = tcore_object_get_hal(co_ps);
532 tcore_check_return_assert(at_resp != NULL);
533 tcore_check_return_assert(ps_context != NULL);
535 (void)tcore_context_get_id(ps_context, &context_id);
536 dbg("Context ID : %d", context_id);
539 * AT+CGACT = 0 is returning NO CARRIER or an error. Just test if the
540 * response contains NO CARRIER else decode CME error.
543 if (at_resp->success) {
546 line = (const gchar *)at_resp->lines->data;
547 if (g_strcmp0(line, "NO CARRIER") != 0) {
549 err("Context %d has not been deactivated", context_id);
556 __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED);
558 if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id, FALSE) != TEL_RETURN_SUCCESS)
559 err("Failed to disable network interface");
562 static void on_response_imc_ps_define_context(TcorePending *p,
563 guint data_len, const void *data, void *user_data)
565 const TcoreAtResponse *at_resp = data;
566 CoreObject *ps_context = (CoreObject *) user_data;
567 CoreObject *co_ps = tcore_pending_ref_core_object(p);
568 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
572 tcore_check_return_assert(at_resp != NULL);
573 tcore_check_return_assert(ps_context != NULL);
574 tcore_check_return_assert(private_info != NULL);
576 if (at_resp->success) {
577 dbg("Response OK,Sending DNS enable command");
578 __imc_ps_send_xdns_enable_cmd(co_ps, ps_context);
581 TcorePsCallState curr_call_status;
583 err("ERROR[%s]", at_resp->final_response);
584 (void)tcore_context_get_id(ps_context, &context_id);
585 curr_call_status = private_info->ps_call_status;
586 __notify_context_status_changed(co_ps, context_id, curr_call_status);
591 * Operation - PDP Context Activate
594 * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
598 * indicates the state of PDP context activation
603 * It is a numeric parameter which specifies a particular PDP context definition
606 * Success: (No Result)
609 * +CME ERROR: <error>
612 static TelReturn imc_ps_activate_context(CoreObject *co_ps, CoreObject *ps_context,
613 TcoreObjectResponseCallback cb, void *cb_data)
615 TelReturn ret = TEL_RETURN_FAILURE;
616 gchar *at_cmd = NULL;
618 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
620 tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
624 (void)tcore_context_get_id(ps_context, &context_id);
625 dbg("Context ID : %d", context_id);
627 at_cmd = g_strdup_printf("AT+CGACT=1,%d", context_id);
628 dbg(" at command : %s", at_cmd);
630 /* Send Request to modem */
631 ret = tcore_at_prepare_and_send_request(co_ps,
633 TCORE_AT_COMMAND_TYPE_NO_RESULT,
635 on_response_imc_ps_activate_context,
637 on_send_imc_request, NULL);
638 if (ret != TEL_RETURN_SUCCESS){
639 TcorePsCallState curr_call_status;
640 curr_call_status = private_info->ps_call_status;
641 err("AT request failed. Send notification for call status [%d]", curr_call_status);
642 __notify_context_status_changed(co_ps, context_id, curr_call_status);
649 * Operation - PDP Context Deactivate
652 * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
656 * indicates the state of PDP context activation
661 * It is a numeric parameter which specifies a particular PDP context definition
664 * Success: (No Result)
667 * +CME ERROR: <error>
669 static TelReturn imc_ps_deactivate_context(CoreObject *co_ps, CoreObject *ps_context,
670 TcoreObjectResponseCallback cb, void *cb_data)
672 TelReturn ret = TEL_RETURN_FAILURE;
673 gchar *at_cmd = NULL;
675 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
677 tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
681 (void)tcore_context_get_id(ps_context, &context_id);
682 dbg("Context ID : %d", context_id);
684 at_cmd = g_strdup_printf("AT+CGACT=0,%d", context_id);
685 dbg(" at command : %s", at_cmd);
687 /* Send Request to modem */
688 ret = tcore_at_prepare_and_send_request(co_ps,
690 TCORE_AT_COMMAND_TYPE_NO_RESULT,
692 on_response_imc_ps_deactivate_context,
694 on_send_imc_request, NULL);
695 if (ret != TEL_RETURN_SUCCESS){
696 TcorePsCallState curr_call_status;
697 curr_call_status = private_info->ps_call_status;
698 err("AT request failed. Send notification for call status [%d]", curr_call_status);
699 __notify_context_status_changed(co_ps, context_id, curr_call_status);
706 * Operation - Define PDP Context
709 * AT-Command: AT+CGDCONT= [<cid> [, <PDP_type> [, <APN> [, <PDP_addr> [,
710 * <d_comp> [, <h_comp> [, <pd1> [... [, pdN]]]]]]]]]
713 * It is a numeric parameter, which specifies a particular PDP context definition
716 * "IP" Internet Protocol (IETF STD 5)
717 * "IPV6" Internet Protocol, version 6 (IETF RFC 2460)
718 * "IPV4V6" Virtual <PDP_type>introduced to handle dual IP stack UE capability (see 3GPP
725 * It is the string parameter that identifies the MT in the address space applicable to the PDP
726 * The allocated address may be read using the command +CGPADDR command
729 * A numeric parameter that controls PDP data compression
735 * A numeric parameter that controls PDP header compression
743 * zero to N string parameters whose meanings are specific to the <PDP_type>
746 * Success: (No Result)
749 * +CME ERROR: <error>
751 static TelReturn imc_ps_define_context(CoreObject *co_ps, CoreObject *ps_context,
752 TcoreObjectResponseCallback cb, void *cb_data)
754 TelReturn ret = TEL_RETURN_FAILURE;
755 gchar *at_cmd = NULL;
756 guint context_id = 0;
758 gchar *pdp_type_str = NULL;
759 TcoreContextType pdp_type;
760 TcoreContextDComp d_comp;
761 TcoreContextHComp h_comp;
762 TcorePsCallState curr_call_status;
764 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
766 tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
770 (void)tcore_context_get_id(ps_context, &context_id);
771 (void)tcore_context_get_type(ps_context, &pdp_type);
774 case TCORE_CONTEXT_TYPE_X25:
775 dbg("CONTEXT_TYPE_X25");
776 pdp_type_str = g_strdup("X.25");
779 case TCORE_CONTEXT_TYPE_IP:
780 dbg("CONTEXT_TYPE_IP");
781 pdp_type_str = g_strdup("IP");
784 case TCORE_CONTEXT_TYPE_PPP:
785 dbg("CONTEXT_TYPE_PPP");
786 pdp_type_str = g_strdup("PPP");
789 case TCORE_CONTEXT_TYPE_IPV6:
790 dbg("CONTEXT_TYPE_IPV6");
791 pdp_type_str = g_strdup("IPV6");
795 /*PDP Type not supported*/
796 dbg("Unsupported PDP type: %d", pdp_type);
800 (void)tcore_context_get_data_compression(ps_context, &d_comp);
801 (void)tcore_context_get_header_compression(ps_context, &h_comp);
802 (void)tcore_context_get_apn(ps_context, &apn);
804 dbg("Define context for CID: %d", context_id);
807 at_cmd = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", context_id, pdp_type_str, apn, d_comp, h_comp);
808 dbg("AT Command : %s", at_cmd);
810 /* Send Request to modem */
811 ret = tcore_at_prepare_and_send_request(co_ps,
813 TCORE_AT_COMMAND_TYPE_NO_RESULT,
815 on_response_imc_ps_define_context,
817 on_send_imc_request, NULL);
819 tcore_free(pdp_type_str);
823 if (ret == TEL_RETURN_SUCCESS)
827 err("Failed to prepare and send AT request");
829 curr_call_status = private_info->ps_call_status;
830 __notify_context_status_changed(co_ps, context_id, curr_call_status);
837 static TcorePsOps imc_ps_ops = {
838 .define_context = imc_ps_define_context,
839 .activate_context = imc_ps_activate_context,
840 .deactivate_context = imc_ps_deactivate_context
844 gboolean imc_ps_init(TcorePlugin *p, CoreObject *co)
846 PrivateInfo *private_info;
850 /* Set PrivateInfo */
851 private_info = tcore_malloc0(sizeof(PrivateInfo));
852 tcore_object_link_user_data(co, private_info);
855 tcore_ps_set_ops(co, &imc_ps_ops);
858 tcore_object_add_callback(co, "+CGEV", on_notification_imc_ps_cgev, NULL);
860 tcore_plugin_add_notification_hook(p,
861 TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS,
862 on_hook_imc_nw_registration_status, co);
868 void imc_ps_exit(TcorePlugin *p, CoreObject *co)
870 PrivateInfo *private_info;
872 private_info = tcore_object_ref_user_data(co);
873 tcore_check_return_assert(private_info != NULL);
875 tcore_free(private_info);