Initial commit 62/70062/1
authorWootak Jung <wootak.jung@samsung.com>
Wed, 18 May 2016 02:38:28 +0000 (11:38 +0900)
committerWootak Jung <wootak.jung@samsung.com>
Wed, 18 May 2016 02:38:28 +0000 (11:38 +0900)
Change-Id: Id9320a3d83b0af92bab9d9cf9c738245f1280e85

13 files changed:
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
include/atd_modem.h [new file with mode: 0644]
include/atd_network.h [new file with mode: 0644]
include/atd_ps.h [new file with mode: 0644]
include/atd_sim.h [new file with mode: 0644]
packaging/tel-plugin-atdongle.spec [new file with mode: 0644]
src/atd_modem.c [new file with mode: 0644]
src/atd_network.c [new file with mode: 0644]
src/atd_ps.c [new file with mode: 0644]
src/atd_sim.c [new file with mode: 0644]
src/desc-atdongle.c [new file with mode: 0644]
tel-plugin-atdongle.manifest [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8955b6e
--- /dev/null
@@ -0,0 +1,52 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(atdongle-plugin C)
+
+#INCLUDE(FindPkgConfig)
+SET(LIBNAME atdongle-plugin)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR ${LIB_INSTALL_DIR})
+SET(INCLUDEDIR "\${prefix}/include")
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED glib-2.0 tcore dlog key-manager)
+
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+                               )
+
+SET(ADDITIONAL_CFLAGS "-Werror -Wall -Wcast-qual -Wno-array-bounds -Wno-empty-body -Wno-ignored-qualifiers -Wshadow -Wwrite-strings -Wswitch-default -Wno-unused-but-set-parameter -Wno-unused-but-set-variable -Wmaybe-uninitialized -Wuninitialized")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wdeclaration-after-statement -Wmissing-declarations -Wredundant-decls -Wcast-align")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ADDITIONAL_CFLAGS}")
+
+ADD_DEFINITIONS("-DFEATURE_TLOG_DEBUG")
+ADD_DEFINITIONS ("-DTIZEN_DEBUG_ENABLE")
+ADD_DEFINITIONS("-DTCORE_LOG_TAG=\"ATDONGLE\"")
+
+MESSAGE(${CMAKE_C_FLAGS})
+MESSAGE(${CMAKE_EXE_LINKER_FLAGS})
+
+SET(SRCS
+               src/desc-atdongle.c
+               src/atd_modem.c
+               src/atd_network.c
+               src/atd_sim.c
+               src/atd_ps.c
+)
+
+# library build
+ADD_LIBRARY(${LIBNAME} SHARED ${SRCS})
+TARGET_LINK_LIBRARIES(${LIBNAME} ${pkgs_LDFLAGS})
+SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "" OUTPUT_NAME ${LIBNAME})
+
+
+# install
+INSTALL(TARGETS ${LIBNAME}
+       LIBRARY DESTINATION ${LIB_INSTALL_DIR}/telephony/plugins/modems)
+
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME tel-plugin-atdongle)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..0f31839
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,204 @@
+Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/include/atd_modem.h b/include/atd_modem.h
new file mode 100644 (file)
index 0000000..b65f0b1
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ATD_MODEM_H__
+#define __ATD_MODEM_H__
+
+gboolean atd_modem_init(TcorePlugin *p, CoreObject *co_modem);
+void atd_modem_exit(TcorePlugin *p, CoreObject *co_modem);
+
+gboolean modem_power_on(TcorePlugin *plugin);
+
+#endif
diff --git a/include/atd_network.h b/include/atd_network.h
new file mode 100644 (file)
index 0000000..8c7d90f
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ATD_NETWORK_H__
+#define __ATD_NETWORK_H__
+
+gboolean atd_network_init(TcorePlugin *p, CoreObject *co_network);
+void atd_network_exit(TcorePlugin *p, CoreObject *co_network);
+
+#endif
diff --git a/include/atd_ps.h b/include/atd_ps.h
new file mode 100644 (file)
index 0000000..35303c4
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ATD_PS_H__
+#define __ATD_PS_H__
+
+gboolean atd_ps_init(TcorePlugin *p, CoreObject *co_ps);
+void atd_ps_exit(TcorePlugin *p, CoreObject *co_ps);
+
+#endif /*__ATD_PS_H__*/
diff --git a/include/atd_sim.h b/include/atd_sim.h
new file mode 100644 (file)
index 0000000..d623dcd
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ATD_SIM_H__
+#define __ATD_SIM_H__
+
+gboolean atd_sim_init(TcorePlugin *p, CoreObject *co_sim);
+void atd_sim_exit(TcorePlugin *p, CoreObject *co_sim);
+
+gboolean get_sim_status(TcorePlugin *plugin);
+
+#endif
diff --git a/packaging/tel-plugin-atdongle.spec b/packaging/tel-plugin-atdongle.spec
new file mode 100644 (file)
index 0000000..06d0ffe
--- /dev/null
@@ -0,0 +1,51 @@
+Name:          tel-plugin-atdongle
+Summary:       AT dongle plugin for telephony
+Version:       0.1.35
+Release:       1
+Group:         Development/Libraries
+License:       Apache-2.0
+Source0:       tel-plugin-atdongle-%{version}.tar.gz
+Requires(post):        /sbin/ldconfig
+Requires(postun):/sbin/ldconfig
+BuildRequires: cmake
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(tcore)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(key-manager)
+
+# This package would be built only TV
+%if "%{?tizen_profile_name}" != "tv"
+ExcludeArch: %{arm} %ix86 x86_64
+%endif
+
+%if "%{?_repository}" == "emulator"
+ExcludeArch: %{arm} %ix86 x86_64
+%endif
+
+%description
+AT dongle plugin for telephony
+
+%prep
+%setup -q
+
+%build
+%cmake .
+make %{?jobs:-j%jobs}
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%install
+rm -rf %{buildroot}
+%make_install
+mkdir -p %{buildroot}/usr/share/license
+cp LICENSE %{buildroot}/usr/share/license/%{name}
+
+%files
+%manifest tel-plugin-atdongle.manifest
+%defattr(-,root,root,-)
+%{_libdir}/telephony/plugins/modems/*
+/usr/share/license/%{name}
diff --git a/src/atd_modem.c b/src/atd_modem.c
new file mode 100644 (file)
index 0000000..900e344
--- /dev/null
@@ -0,0 +1,562 @@
+/*
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <glib.h>
+
+#include <tcore.h>
+#include <hal.h>
+#include <core_object.h>
+#include <plugin.h>
+#include <user_request.h>
+#include <queue.h>
+#include <co_modem.h>
+#include <server.h>
+#include <at.h>
+
+#include "atd_modem.h"
+#include "atd_sim.h"
+
+#define IMEI_LEN_MAX           16
+#define DONGLE_NAME_LEN_MAX    32
+
+typedef struct {
+       gboolean device_info;
+       gboolean imei_valid;
+       char imei[IMEI_LEN_MAX+1];
+
+       gboolean modem_power_on;
+       gboolean device_info_valid;
+       char vendor_name[DONGLE_NAME_LEN_MAX+1];
+       char device_name[DONGLE_NAME_LEN_MAX+1];
+} PrivateObject;
+
+static void on_response_get_device_info(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       UserRequest *ur = tcore_pending_ref_user_request(p);
+       struct tresp_modem_get_device_info res = {0,};
+       CoreObject *co = tcore_pending_ref_core_object(p);
+       PrivateObject *po = tcore_object_ref_user_data(co);
+
+
+       dbg("Entry");
+
+       if (resp && resp->success) {
+               GSList *lines;
+               const char *line;
+               int line_index = 0;
+
+               dbg("RESPONSE OK");
+               dbg("resp->lines[%p]", resp->lines);
+               res.result = TCORE_RETURN_SUCCESS;
+               /* Make device_info TRUE, no need to fetch device info again */
+               po->device_info = TRUE;
+
+               lines = resp->lines;
+               while (lines) {
+                       line = (const char *)lines->data;
+                       line_index++;
+
+                       /* AT+CGMI;+CGMM;+CGSN
+                        * <CR><LF><manufacturer><CR><LF>
+                        * <CR><LF><model><CR><LF>
+                        * <CR><LF><imei><CR><LF>
+                        * <CR><LF>OK<CR><LF>
+                        */
+                       if (line_index == 2) {
+                               /* Manufacturer */
+                               snprintf(po->vendor_name, DONGLE_NAME_LEN_MAX+1, "%s", line);
+                               dbg("Vendor name: [%s]", po->vendor_name);
+
+                               po->device_info_valid = TRUE;
+                       } else if (line_index == 3) {
+                               /* Model */
+                               snprintf(po->device_name, DONGLE_NAME_LEN_MAX+1, "%s", line);
+                               dbg("Device name: [%s]", po->device_name);
+
+                               po->device_info_valid = TRUE;
+                       } else if (line_index == 4) {
+                               /* IMEI */
+                               snprintf(po->imei, IMEI_LEN_MAX+1, "%s", line);
+                               dbg("IMEI: [%s]", po->imei);
+
+                               po->imei_valid = TRUE;
+                       } else {
+                               dbg("Neglecting line - [%s]", line);
+                       }
+
+                       /* Move to next line */
+                       lines = lines->next;
+               }
+       } else {
+               err("RESPONSE NOK");
+               res.result = TCORE_RETURN_FAILURE;
+       }
+
+       if (ur) {
+               /* External request */
+               dbg("Send TRESP_MODEM_GET_DEVICE_INFO Response");
+               if (res.result == TCORE_RETURN_SUCCESS) {
+                       g_strlcpy(res.device_name, po->device_name,
+                                               strlen(po->device_name) + 1);
+                       g_strlcpy(res.vendor_name, po->vendor_name,
+                                               strlen(po->vendor_name) + 1);
+               }
+
+               /* Send Response */
+               tcore_user_request_send_response(ur,
+                       TRESP_MODEM_GET_DEVICE_INFO,
+                       sizeof(struct tresp_modem_get_device_info), &res);
+       }
+}
+
+static TReturn __get_device_info(CoreObject *co, UserRequest *ur)
+{
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       /* Get device information */
+       ret = tcore_prepare_and_send_at_request(co,
+               "AT+CGMI;+CGMM;+CGSN", NULL,
+               TCORE_AT_MULTILINE,
+               ur,
+               on_response_get_device_info, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+
+       return ret;
+}
+
+static enum tcore_hook_return on_hook_modem_plugin_completed(Server *s,
+       CoreObject *source,
+       enum tcore_notification_command command,
+       unsigned int data_len, void *data, void *user_data)
+{
+       CoreObject *co_modem = (CoreObject *)user_data;
+       gboolean dongle_added = TRUE;
+       PrivateObject  *po = NULL;
+
+       dbg("Enter");
+       if (co_modem == NULL) {
+               err("CoreObject is NULL");
+               return TCORE_HOOK_RETURN_CONTINUE;
+       }
+       po = tcore_object_ref_user_data(co_modem);
+
+       /*
+        * Send Notification
+        *      - Dongle status added
+        */
+       tcore_server_send_notification(s, co_modem,
+               TNOTI_MODEM_DONGLE_STATUS,
+               sizeof(gboolean), &dongle_added);
+
+       /*
+        * Send Notification
+        *      - Modem added
+        */
+       tcore_server_send_notification(s, co_modem,
+               TNOTI_MODEM_ADDED,
+               0, NULL);
+
+       if (po && po->modem_power_on) {
+               struct tnoti_modem_power modem_power = {0, };
+
+               /* Send Notification to TAPI - MODEM_POWER */
+               modem_power.state = MODEM_STATE_ONLINE;
+               dbg("Sending notification - Modem Power state: [ONLINE]");
+
+               tcore_server_send_notification(s, co_modem,
+                       TNOTI_MODEM_POWER,
+                       sizeof(modem_power), &modem_power);
+
+               /*
+                * Send Notification
+                *      - Dongle login success
+                *        : some dongles which use their own API require authorization.
+                *          Provide same response with them.
+                *          it is always true for AT command dongle.
+                */
+               tcore_server_send_notification(s, co_modem,
+                       TNOTI_MODEM_DONGLE_LOGIN,
+                       sizeof(gboolean), &dongle_added);
+       } else {
+               err("PO [%p] is NULL or modem is not powered on !", po);
+       }
+
+       return TCORE_HOOK_RETURN_CONTINUE;
+}
+
+static enum tcore_hook_return on_hook_sim_init(Server *s, CoreObject *source,
+       enum tcore_notification_command command,
+       unsigned int data_len, void *data, void *user_data)
+{
+       CoreObject *co_modem = (CoreObject *)user_data;
+       const struct tnoti_sim_status *sim = data;
+       PrivateObject  *po;
+
+       dbg("Enter");
+
+       if (co_modem == NULL) {
+               err("Invalid core object !");
+               return TCORE_HOOK_RETURN_CONTINUE;
+       }
+
+       if (!sim) {
+               err("Invalid data");
+               return TCORE_HOOK_RETURN_CONTINUE;
+       }
+
+       /* Fetch device info only once*/
+       po = tcore_object_ref_user_data(co_modem);
+       if (po && po->device_info == FALSE) {
+               dbg("Fetch device information");
+               __get_device_info(co_modem, NULL);
+       }
+
+       dbg("Exit");
+       return TCORE_HOOK_RETURN_CONTINUE;
+}
+
+static void on_response_get_imei(TcorePending *p,
+       int data_len, const void *data,
+       void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       struct tresp_modem_get_imei res = {0,};
+       UserRequest *ur = NULL;
+       GSList *tokens = NULL;
+       const char *line;
+       res.result = TCORE_RETURN_FAILURE;
+
+       if (resp && resp->success) {
+               dbg("RESPONSE OK");
+               if (resp->lines) {
+                       line = (const char *) resp->lines->data;
+                       tokens = tcore_at_tok_new(line);
+                       if (g_slist_length(tokens) != 1) {
+                               err("invalid message");
+                               goto OUT;
+                       }
+
+                       /* Copy IMEI */
+                       g_strlcpy(res.imei, g_slist_nth_data(tokens, 0),
+                                               IMEI_LEN_MAX + 1);
+                       res.result = TCORE_RETURN_SUCCESS;
+                       goto OUT;
+               }
+       }
+
+       err("RESPONSE NOK");
+       if (resp && resp->lines) {
+               int response = 0;
+               const char *check = NULL;
+               line = (const char *) resp->lines->data;
+               tokens = tcore_at_tok_new(line);
+               if (g_slist_length(tokens) == 1) {
+                       check = g_slist_nth_data(tokens, 0);
+                       if (check) {
+                               response = atoi(check);
+                               /* TODO: CMEE error mapping is required. */
+                               err("Response: [%d]", response);
+                       } else {
+                               err("Unexpected response: [%s]", line);
+                       }
+               }
+       }
+OUT:
+       ur = tcore_pending_ref_user_request(p);
+       tcore_user_request_send_response(ur,
+               TRESP_MODEM_GET_IMEI,
+               sizeof(struct tresp_modem_get_imei), &res);
+
+       /* Free resources */
+       tcore_at_tok_free(tokens);
+}
+
+static void on_response_modem_power_on(TcorePending *p,
+       int data_len, const void *data,
+       void *user_data)
+{
+       CoreObject *co = NULL;
+       TcorePlugin *plugin = NULL;
+       gboolean ret;
+       const TcoreATResponse *resp = data;
+
+       if (resp && resp->success) {
+               dbg("RESPONSE OK");
+
+               /* Get SIM status */
+               co = tcore_pending_ref_core_object(p);
+               plugin = tcore_object_ref_plugin(co);
+               ret = get_sim_status(plugin);
+               dbg("ret[%d]", ret);
+       } else {
+               err("RESPONSE NOK");
+       }
+}
+
+static void on_response_power_off(TcorePending *p,
+       int data_len, const void *data,
+       void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       struct tresp_modem_power_off pwr_resp;
+       UserRequest *ur = NULL;
+
+       if (resp && resp->success) {
+               CoreObject *co = NULL;
+               TcoreHal *h = NULL;
+
+               dbg("RESPONSE OK");
+
+               pwr_resp.result = TCORE_RETURN_SUCCESS;
+
+               /* Set HAL state to 'FALSE' */
+               co = tcore_pending_ref_core_object(p);
+               h = tcore_object_get_hal(co);
+               tcore_hal_set_power_state(h, FALSE);
+
+       } else {
+               err("RESPONSE NOK");
+               pwr_resp.result = TCORE_RETURN_FAILURE;
+       }
+
+       ur = tcore_pending_ref_user_request(p);
+       tcore_user_request_send_response(ur,
+               TRESP_MODEM_POWER_OFF,
+               sizeof(struct tresp_modem_power_off), &pwr_resp);
+}
+
+/**< Modem Power ON */
+gboolean modem_power_on(TcorePlugin *plugin)
+{
+       PrivateObject *po = NULL;
+       CoreObject *co_modem = NULL;
+       TReturn ret = TCORE_RETURN_FAILURE;
+       gboolean result = FALSE;
+
+       co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
+       if (co_modem == NULL) {
+               err("Modem Core object is NULL");
+               return result;
+       }
+       po = tcore_object_ref_user_data(co_modem);
+
+       /* Radio ON */
+       ret = tcore_prepare_and_send_at_request(co_modem,
+               "AT+CFUN=1", NULL,
+               TCORE_AT_NO_RESULT,
+               NULL,
+               on_response_modem_power_on, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+       if (ret == TCORE_RETURN_SUCCESS) {
+               /* Set Modem Power State to 'ON' */
+               tcore_modem_set_powered(co_modem, TRUE);
+
+               /* To send notification to TAPI - MODEM_POWER */
+               if (po)
+                       po->modem_power_on = TRUE;
+
+               result = TRUE;
+       } else {
+               err("ret: [0x%x]", ret);
+       }
+
+       return result;
+}
+
+/**< Modem Power OFF */
+static TReturn atd_modem_power_off(CoreObject *co, UserRequest *ur)
+{
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       ret = tcore_prepare_and_send_at_request(co,
+               "AT+CFUN=0", NULL,
+               TCORE_AT_NO_RESULT,
+               ur,
+               on_response_power_off, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+
+       return ret;
+}
+
+/**< Get IMEI */
+static TReturn atd_modem_get_imei(CoreObject *co, UserRequest *ur)
+{
+       PrivateObject *po = tcore_object_ref_user_data(co);
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       if (po->imei_valid == TRUE) {
+               struct tresp_modem_get_imei res = {0,};
+
+               g_strlcpy(res.imei,  po->imei, IMEI_LEN_MAX + 1);
+               res.result = TCORE_RETURN_SUCCESS;
+               dbg("IMEI information - Available!!! IMEI [%s]", po->imei);
+
+               /* Send Response */
+               ret = tcore_user_request_send_response(ur,
+                       TRESP_MODEM_GET_IMEI,
+                       sizeof(struct tresp_modem_get_imei), &res);
+       } else  {
+               dbg("IMEI information - Not Available, fetching from Modem");
+
+               ret = tcore_prepare_and_send_at_request(co,
+                       "AT+CGSN", NULL,
+                       TCORE_AT_NUMERIC,
+                       ur,
+                       on_response_get_imei, NULL,
+                       NULL, NULL,
+                       0, NULL, NULL);
+       }
+
+       dbg("ret: [0x%x]", ret);
+       return ret;
+}
+
+/**< Get Device information */
+static TReturn atd_modem_get_device_info(CoreObject *co, UserRequest *ur)
+{
+       PrivateObject *po = tcore_object_ref_user_data(co);
+       TReturn ret = TCORE_RETURN_FAILURE;
+       dbg("Entry");
+
+       if (po->device_info_valid == TRUE) {
+               struct tresp_modem_get_device_info res = {0,};
+
+               dbg("Device information - Available");
+
+               res.result = TCORE_RETURN_SUCCESS;
+               g_strlcpy(res.device_name, po->device_name,
+                                       strlen(po->device_name) + 1);
+               g_strlcpy(res.vendor_name, po->vendor_name,
+                                       strlen(po->vendor_name) + 1);
+               dbg("Vendor name: [%s] Device name: [%s]",
+                                       po->vendor_name, po->device_name);
+
+               /* Send Response */
+               ret = tcore_user_request_send_response(ur,
+                       TRESP_MODEM_GET_DEVICE_INFO,
+                       sizeof(struct tresp_modem_get_device_info), &res);
+       } else {
+               dbg("Device information - Not Available, fetching from Modem");
+
+               ret = __get_device_info(co, ur);
+               dbg("ret: [0x%x]", ret);
+       }
+
+       return ret;
+}
+
+/**< Modem Operations */
+static struct tcore_modem_operations modem_ops = {
+       .power_on = NULL,
+       .power_off = atd_modem_power_off,
+       .power_reset = NULL,
+       .power_low = NULL,
+       .set_flight_mode = NULL,
+       .get_imei = atd_modem_get_imei,
+       .get_version = NULL,
+       .get_sn = NULL,
+       .dun_pin_ctrl = NULL,
+       .get_flight_mode = NULL,
+       .get_device_info = atd_modem_get_device_info,
+};
+
+/**< Modem init function */
+gboolean atd_modem_init(TcorePlugin *p, CoreObject *co_modem)
+{
+       Server *s = tcore_plugin_ref_server(tcore_object_ref_plugin(co_modem));
+       PrivateObject *po;
+
+       dbg("Enter");
+
+       /* Set operations */
+       tcore_modem_set_ops(co_modem, &modem_ops, TCORE_OPS_TYPE_CP);
+
+       po = g_malloc0(sizeof(PrivateObject));
+       tcore_object_link_user_data(co_modem, po);
+
+       /* Wait for sim init */
+       tcore_server_add_notification_hook(s,
+               TNOTI_SIM_STATUS,
+               on_hook_sim_init, co_modem);
+
+       /*
+        * Wait for adding modem plugin completion
+        *  - to Send dongle/modem 'added' notification
+        */
+       tcore_server_add_notification_hook(s,
+               TNOTI_SERVER_ADDED_MODEM_PLUGIN_COMPLETED,
+               on_hook_modem_plugin_completed, co_modem);
+
+       return TRUE;
+}
+
+/**< Modem exit function */
+void atd_modem_exit(TcorePlugin *p, CoreObject *co_modem)
+{
+       Server *s = tcore_plugin_ref_server(tcore_object_ref_plugin(co_modem));
+       PrivateObject *po;
+       gboolean dongle_added = FALSE;
+
+       dbg("Enter");
+
+       /*
+        * Send Notification
+        *      - Dongle logout :
+        *        : some dongles which use their own API require authorization.
+        *          Provide same response with them.
+        *          reset its value to false.
+        *      - Dongle removed notification
+        */
+       tcore_server_remove_notification_hook(s, on_hook_sim_init);
+       tcore_server_remove_notification_hook(s, on_hook_modem_plugin_completed);
+
+       tcore_server_send_notification(s, co_modem,
+               TNOTI_MODEM_DONGLE_LOGIN,
+               sizeof(gboolean), &dongle_added);
+       tcore_server_send_notification(s, co_modem,
+               TNOTI_MODEM_DONGLE_STATUS,
+               sizeof(gboolean), &dongle_added);
+
+       /* Unset 'ops' */
+       tcore_modem_set_ops(co_modem, NULL, TCORE_OPS_TYPE_CP);
+
+       po = tcore_object_ref_user_data(co_modem);
+       g_free(po);
+
+       dbg("Exit");
+}
diff --git a/src/atd_network.c b/src/atd_network.c
new file mode 100644 (file)
index 0000000..35adf3f
--- /dev/null
@@ -0,0 +1,1301 @@
+/*
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <tcore.h>
+#include <hal.h>
+#include <core_object.h>
+#include <plugin.h>
+#include <user_request.h>
+#include <queue.h>
+#include <co_network.h>
+#include <co_ps.h>
+#include <server.h>
+#include <storage.h>
+#include <util.h>
+#include <at.h>
+
+#include "atd_network.h"
+
+#define RSSI_POLLING_TIMEOUT   30
+
+#define AT_COPS_ACT_GSM                 0   /* GSM */
+#define AT_COPS_ACT_GSM_COMPACT         1   /* GSM Compact */
+#define AT_COPS_ACT_UTRAN               2   /* UTRAN */
+#define AT_COPS_ACT_GSM_EGPRS           3   /* GSM w/EGPRS */
+#define AT_COPS_ACT_UTRAN_HSDPA         4   /* UTRAN w/HSDPA */
+#define AT_COPS_ACT_UTRAN_HSUPA         5   /* UTRAN w/HSUPA */
+#define AT_COPS_ACT_UTRAN_HSDPA_HSUPA   6   /* UTRAN w/HSDPA and HSUPA */
+#define AT_COPS_ACT_E_UTRAN             7   /* E-UTRAN */
+#define AT_COPS_ACT_VALUE_MAX           8
+
+struct network_reg_status_cb_data {
+       struct tnoti_network_registration_status regist_status;
+};
+
+typedef struct {
+       gboolean subscribe_creg_event;
+       gboolean subscribe_cgreg_event;
+       guint rssi_src_id;
+} PrivateObject;
+
+static TReturn get_serving_network(CoreObject *co, UserRequest *ur);
+static void __handle_ps_network_status(CoreObject *co, int stat);
+static void __handle_cs_network_status(CoreObject *co, int stat);
+
+static int __convert_rssi_bar(int rssi)
+{
+       int rssi_dBm = 0, rssi_bar = 0;
+       int table[5] = {-113, -106, -100, -90, -80};    /* (0~5 level) */
+
+       /* <rssi>
+        * 0    : -113 dBm or less
+        * 1    : -111 dBm
+        * 2~30 : -109 ~ -53 dBm
+        * 31   : -51 dBm or greater
+        * 99   : not known or not detectable
+        */
+       rssi_dBm = -113 + rssi*2;
+
+       if (rssi_dBm > table[4])
+               rssi_bar = 5;   /* antenna bar : 5 */
+       else if (rssi_dBm > table[3])
+               rssi_bar = 4;   /* antenna bar : 4 */
+       else if (rssi_dBm > table[2])
+               rssi_bar = 3;   /* antenna bar : 3 */
+       else if (rssi_dBm > table[1])
+               rssi_bar = 2;   /* antenna bar : 2 */
+       else if (rssi_dBm > table[0])
+               rssi_bar = 1;   /* antenna bar : 1 */
+       else
+               rssi_bar = 0;   /* antenna bar : 0 */
+
+       dbg("rssi[%d, %d(dBm)] -> rssi_bar[%d]", rssi, rssi_dBm, rssi_bar);
+
+       return rssi_bar;
+}
+
+static unsigned int lookup_tbl_access_technology[] = {
+       [AT_COPS_ACT_GSM] = NETWORK_ACT_GSM,
+       [AT_COPS_ACT_GSM_COMPACT] = NETWORK_ACT_GSM,
+       [AT_COPS_ACT_UTRAN] = NETWORK_ACT_UTRAN,
+       [AT_COPS_ACT_GSM_EGPRS] = NETWORK_ACT_EGPRS,
+       [AT_COPS_ACT_UTRAN_HSDPA] = NETWORK_ACT_UTRAN,
+       [AT_COPS_ACT_UTRAN_HSUPA] = NETWORK_ACT_UTRAN,
+       [AT_COPS_ACT_UTRAN_HSDPA_HSUPA] = NETWORK_ACT_UTRAN,
+       [AT_COPS_ACT_E_UTRAN] = NETWORK_ACT_GSM_UTRAN,
+};
+
+static enum telephony_network_service_domain_status
+       __mapping_network_status(int stat)
+{
+       switch (stat) {
+       case 0:
+       case 4:
+               return NETWORK_SERVICE_DOMAIN_STATUS_NO;
+
+       case 1:
+               return NETWORK_SERVICE_DOMAIN_STATUS_FULL;
+
+       case 2:
+               return NETWORK_SERVICE_DOMAIN_STATUS_SEARCH;
+
+       case 3:
+               return NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY;
+
+       case 5:
+               return NETWORK_SERVICE_DOMAIN_STATUS_FULL;
+
+       default:
+               return NETWORK_SERVICE_DOMAIN_STATUS_NO;
+       }
+}
+
+static enum telephony_network_service_type
+       _get_service_type(enum telephony_network_service_type prev_type,
+               int act, int cs_status, int ps_status)
+{
+       enum telephony_network_service_type ret;
+       dbg("Enter");
+
+       ret = prev_type;
+
+       switch (act) {
+       case NETWORK_ACT_UNKNOWN:
+               ret = NETWORK_SERVICE_TYPE_UNKNOWN;
+       break;
+       case NETWORK_ACT_GSM:
+               ret = NETWORK_SERVICE_TYPE_2G;
+       break;
+       case NETWORK_ACT_UMTS:
+               ret = NETWORK_SERVICE_TYPE_3G;
+       break;
+       case NETWORK_ACT_LTE:
+               ret = NETWORK_SERVICE_TYPE_LTE;
+       break;
+       default:
+       break;
+       }
+
+       if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_NO &&
+               ps_status == NETWORK_SERVICE_DOMAIN_STATUS_NO) {
+               ret = NETWORK_SERVICE_TYPE_NO_SERVICE;
+       } else if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_SEARCH ||
+               ps_status == NETWORK_SERVICE_DOMAIN_STATUS_SEARCH) {
+               if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL ||
+                       ps_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL) {
+                       /* no change */
+               } else {
+                       ret = NETWORK_SERVICE_TYPE_SEARCH;
+               }
+       } else if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY ||
+               ps_status == NETWORK_SERVICE_DOMAIN_STATUS_EMERGENCY) {
+               if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL ||
+                       ps_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL) {
+                       /* no change */
+               } else {
+                       ret = NETWORK_SERVICE_TYPE_EMERGENCY;
+               }
+       }
+       dbg("service type[%d]", ret);
+
+       return ret;
+}
+
+static void __ps_set(TcorePlugin *p, int status)
+{
+       CoreObject *co_ps;
+
+       co_ps = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_PS);
+       if (co_ps == NULL) {
+               err("No PS Core Object on plugin");
+               return;
+       }
+
+       if (status == NETWORK_SERVICE_DOMAIN_STATUS_FULL)
+               tcore_ps_set_online(co_ps, TRUE);
+       else
+               tcore_ps_set_online(co_ps, FALSE);
+}
+
+static void __on_response_get_act_information(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       CoreObject *co;
+       GSList *tokens = NULL;
+       const char *line;
+       int AcT = 0;
+       int value = 0;
+       char *pResp = NULL;
+       enum telephony_network_service_type service_type;
+       struct network_reg_status_cb_data *reg_status = user_data;
+       TcorePlugin *plugin = NULL;
+       TReturn ret = TCORE_RETURN_FAILURE;
+       struct tnoti_ps_protocol_status noti = {0,};
+
+       /* +COPS: <mode>[,<format>,<oper>[,<rat>]] */
+       if  (!reg_status) {
+               err("invalid cb data");
+               return;
+       }
+
+       co = tcore_pending_ref_core_object(p);
+       if (resp->success <= 0) {
+               err("RESPONSE NOK");
+               goto OUT;
+       }
+
+       dbg("RESPONSE OK");
+       if (g_slist_length(resp->lines) < 1) {
+               err("invalid message format");
+               goto OUT;
+       }
+
+       line = (const char *)resp->lines->data;
+       tokens = tcore_at_tok_new(line);
+
+       /* mode */
+       if ((pResp = tcore_at_tok_nth(tokens, 0)))
+               dbg("mode  : %s", pResp);
+
+       /*
+        * Skip <format>, <oper>
+        * Parse rat (act)
+        */
+       if ((pResp = tcore_at_tok_nth(tokens, 3))) {
+               dbg("AcT  : %s", pResp);
+               if (!pResp) {
+                       err("ACT is invalid");
+                       goto OUT;
+               }
+               value = atoi(pResp);
+               if (value < AT_COPS_ACT_VALUE_MAX) {
+                       AcT = lookup_tbl_access_technology[value];
+                       tcore_network_set_access_technology(co, AcT);
+               } else {
+                       err("ACT is invalid or missing");
+                       goto OUT;
+               }
+       }
+
+       tcore_network_get_service_type(co, &service_type);
+       dbg("prev_service_type = 0x%x", service_type);
+
+       service_type = _get_service_type(service_type, AcT,
+                       reg_status->regist_status.cs_domain_status,
+                       reg_status->regist_status.ps_domain_status);
+
+       dbg("new_service_type = 0x%x", service_type);
+       tcore_network_set_service_type(co, service_type);
+       reg_status->regist_status.service_type = service_type;
+
+       plugin = tcore_object_ref_plugin(co);
+       tcore_server_send_notification(tcore_plugin_ref_server(plugin),
+               co, TNOTI_NETWORK_REGISTRATION_STATUS,
+               sizeof(struct tnoti_network_registration_status),
+               &(reg_status->regist_status));
+
+       /* Get PLMN ID needed to application */
+       if ((NETWORK_SERVICE_DOMAIN_STATUS_FULL
+                       == reg_status->regist_status.cs_domain_status) ||
+               NETWORK_SERVICE_DOMAIN_STATUS_FULL
+                       == reg_status->regist_status.ps_domain_status) {
+               get_serving_network(co, NULL);
+       }
+
+       /* Update PS Protocal status */
+       switch (value) {
+       case AT_COPS_ACT_GSM:                   /*Fall Through*/
+       case AT_COPS_ACT_GSM_COMPACT:   /*Fall Through*/
+       case AT_COPS_ACT_UTRAN:                 /*Fall Through*/
+       case AT_COPS_ACT_GSM_EGPRS:             /*Fall Through*/
+       case AT_COPS_ACT_E_UTRAN:
+       {
+               dbg("Not required for Protocol Status Notification");
+               goto OUT;
+       }
+       case AT_COPS_ACT_UTRAN_HSDPA:
+       {
+               dbg("HSDPA");
+               noti.status = TELEPHONY_HSDPA_ON;
+               break;
+       }
+       case AT_COPS_ACT_UTRAN_HSUPA:
+       {
+               dbg("HSUPA");
+               noti.status = TELEPHONY_HSUPA_ON;
+               break;
+       }
+       case AT_COPS_ACT_UTRAN_HSDPA_HSUPA:
+       {
+               dbg("HSPA");
+               noti.status = TELEPHONY_HSPA_ON;
+               break;
+       }
+       default:
+       {
+               dbg("Ignore");
+               goto OUT;
+       }
+       }
+
+       ret = tcore_server_send_notification(tcore_plugin_ref_server(plugin),
+                       co, TNOTI_PS_PROTOCOL_STATUS,
+                       sizeof(struct tnoti_ps_protocol_status), &noti);
+
+       dbg("ret: [0x%x]", ret);
+
+OUT:
+       /* Free resources */
+       tcore_at_tok_free(tokens);
+       g_free(reg_status);
+       return;
+}
+
+static TReturn __get_act_information(CoreObject *co, void *user_data)
+{
+       dbg("ENTER!!");
+
+       if (!co)
+               return TCORE_RETURN_EINVAL;
+
+       /* Send Request to modem */
+       tcore_prepare_and_send_at_request(co,
+               "AT+COPS?", "+COPS",
+               TCORE_AT_SINGLELINE,
+               NULL,
+               __on_response_get_act_information, user_data,
+               NULL, NULL,
+               0, NULL, NULL);
+
+       return TCORE_RETURN_SUCCESS;
+}
+
+static guint __get_gslist_length(const GSList *list)
+{
+       guint length = 0;
+       const GSList *iter = NULL;
+
+       for (iter = list; iter; iter = iter->next)
+               length++;
+
+       return length;
+}
+
+static gboolean on_event_ps_network_regist(CoreObject *co,
+       const void *event_info, void *user_data)
+{
+       TcorePlugin *plugin = NULL;
+       Server *server = NULL;
+
+       int stat = 0;
+       unsigned int lac = 0, ci = 0xffff;
+       GSList *tokens = NULL;
+       guint token_count = 0;
+       char *pResp = NULL;
+       char *line = NULL;
+       const GSList *lines = NULL;
+
+       struct tnoti_network_location_cellinfo net_lac_cell_info = {0};
+
+       dbg("+CGREG NOTI RECEIVED");
+       lines = (const GSList *) event_info;
+       if (1 != __get_gslist_length(lines)) {
+               dbg("unsolicited msg but multiple line");
+               goto OUT;
+       }
+
+       line = (char *)(lines->data);
+       if (line == NULL) {
+               err("Invalid message");
+               goto OUT;
+       }
+
+       tokens = tcore_at_tok_new(line);
+       token_count = g_slist_length(tokens);
+       dbg("CGREG token count: %d", token_count);
+       if (token_count == 1) {
+               /* Handle CGREG notification */
+               pResp = g_slist_nth_data(tokens, 0);
+       } else if (token_count == 3) {
+               /* Handle lac */
+               pResp = g_slist_nth_data(tokens, 1);
+               g_strstrip(g_strdelimit(pResp, "\"", ' '));
+               lac = strtol(pResp, NULL, 16);
+               dbg("CGREG token: lac [%x]", lac);
+
+               /* handle ci */
+               pResp = g_slist_nth_data(tokens, 2);
+               g_strstrip(g_strdelimit(pResp, "\"", ' '));
+               ci = strtol(pResp, NULL, 16);
+               dbg("CGREG token: ci [%x]", ci);
+
+               /* Handle CGREG notification */
+               pResp = g_slist_nth_data(tokens, 0);
+       } else {
+               err("Invalid message");
+               goto OUT;
+       }
+
+       if (!pResp) {
+               err("No <stat> in +CGREG");
+               goto OUT;
+       }
+
+       stat = atoi(pResp);
+       __handle_ps_network_status(co, stat);
+
+       tcore_network_set_lac(co, lac);
+       tcore_network_set_cell_id(co, ci);
+
+       net_lac_cell_info.lac = lac;
+       net_lac_cell_info.cell_id = ci;
+
+       plugin = tcore_object_ref_plugin(co);
+       server = tcore_plugin_ref_server(plugin);
+       tcore_server_send_notification(server, co, TNOTI_NETWORK_LOCATION_CELLINFO,
+                       sizeof(struct tnoti_network_location_cellinfo), &net_lac_cell_info);
+OUT:
+       tcore_at_tok_free(tokens);
+       return TRUE;
+}
+
+static gboolean on_event_cs_network_regist(CoreObject *co,
+       const void *event_info, void *user_data)
+{
+       const GSList *lines = NULL;
+       char *line = NULL;
+       int stat = 0;
+       GSList *tokens = NULL;
+       guint token_count = 0;
+       char *pResp = NULL;
+
+       dbg("+CREG NOTI RECEIVED");
+
+       lines = (const GSList *) event_info;
+       if (1 != __get_gslist_length(lines)) {
+               err("unsolicited msg but multiple line");
+               goto OUT;
+       }
+
+       line = (char *) (lines->data);
+       if (line == NULL) {
+               err("Invalid message");
+               goto OUT;
+       }
+
+       /*
+        * +CREG::<n>,<stat>[,<lac>,<ci>]
+        *
+        * <n>:
+        *  0 - Disable proactive reporting of "CREG"
+        *  1 - Enable proactive reporting of "+CREG: <stat>"
+        *  2 - Enable proactive reporting of "+CREG: <stat>[,<lac>,<ci>]"..
+        * <stat>:
+        *  0 - Not registered.
+        *      The MS is not searching the new operators to be registered.
+        *  1 - Local network is registered
+        *  2 - Not registered.
+        *      But the MS is searching the new operators to be registered.
+        *  3 - Registration rejected
+        *  4 - Unknown reasons
+        *  5 - Roaming network is registered
+        * <lac>:
+        * Position code information, composed of four characters and expressed
+        * in hexadecimal. (Example: \9300C3\94\93195\94 in decimal)
+        * <ci>:
+        * Cell information,
+        * composed of four characters and expressed in hexadecimal.
+        * (Extended Information:
+        * according 3GPP Rel7, four characters are requested,
+        * but if before Rel7, for example the currently network is Rel6 mostly,
+        * only the last two  characters is valid, the other characters is invalid
+        * and should be ignored. For example, if the <CI> return 3B3DE1C,
+        * only DE1C is valid and could be used as DE1C is the last two characters.)
+        */
+       tokens = tcore_at_tok_new(line);
+       token_count = g_slist_length(tokens);
+       dbg("CREG token count: %d", token_count);
+       if (token_count == 1 || token_count == 3) {
+               /* Handle CREG notification */
+               pResp = g_slist_nth_data(tokens, 0);
+       } else {
+               err("Invalid message");
+               goto OUT;
+       }
+
+       if (!pResp) {
+               err("No <stat> in +CREG");
+               goto OUT;
+       }
+
+       stat = atoi(pResp);
+       __handle_cs_network_status(co, stat);
+OUT:
+       tcore_at_tok_free(tokens);
+       return TRUE;
+}
+
+static void __on_response_rssi_info(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       CoreObject *co = NULL;
+       const char *line;
+       GSList *tokens = NULL;
+
+       co = tcore_pending_ref_core_object(p);
+       if (!co) {
+               err("Failed to get CoreObject");
+               return;
+       }
+
+       dbg("RSSI Info Response");
+       if (resp && resp->success) {
+               char *rssi_token = NULL;
+
+               dbg("RESPONSE OK");
+
+               line = (const char *) resp->lines->data;
+               tokens = tcore_at_tok_new(line);
+               /* +CSQ: <rssi>,<ber> */
+               if (g_slist_length(tokens) != 2) {
+                       err("invalid response");
+                       goto OUT;
+               }
+
+               rssi_token = (char *) g_slist_nth_data(tokens, 0);
+               if (rssi_token && strlen(rssi_token)) {
+                       TcorePlugin *plugin = NULL;
+                       struct tnoti_network_icon_info net_icon_info = {0,};
+                       int rssi_value = 0;
+
+                       net_icon_info.type = NETWORK_ICON_INFO_RSSI;
+                       rssi_value = atoi(rssi_token);
+                       if (rssi_value == 99) {
+                               warn("Unknown or unmeasurable");
+                               goto OUT;
+                       }
+
+                       net_icon_info.rssi = __convert_rssi_bar(rssi_value);
+
+                       /* Send notification */
+                       plugin = tcore_object_ref_plugin(co);
+                       tcore_server_send_notification(tcore_plugin_ref_server(plugin),
+                               co, TNOTI_NETWORK_ICON_INFO,
+                               sizeof(struct tnoti_network_icon_info),
+                               &net_icon_info);
+               }
+       } else {
+               err("RESPONSE NOK");
+       }
+OUT:
+       tcore_at_tok_free(tokens);
+}
+
+static void on_response_ps_network_status(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       CoreObject *co = NULL;
+       GSList *tokens = NULL;
+       const char *line;
+       int stat = 0;
+       guint token_count = 0;
+       char *pResp = NULL;
+
+       dbg("Enter");
+
+       co = tcore_pending_ref_core_object(p);
+       if (!co) {
+               err("Failed to get CoreObject");
+               return;
+       }
+
+       if (resp && resp->success) {
+               dbg("RESPONSE OK");
+               if (1 != g_slist_length(resp->lines)) {
+                       dbg("unsolicited msg but multiple line");
+                       goto OUT;
+               }
+
+               line = (const char *) resp->lines->data;
+               tokens = tcore_at_tok_new(line);
+               token_count = g_slist_length(tokens);
+               dbg("CGREG token count: %d", token_count);
+
+               if (token_count == 2 || token_count == 4) {
+                       /* Handle CGREG query response */
+                       pResp = g_slist_nth_data(tokens, 1);
+               } else {
+                       err("Invalid message");
+                       goto OUT;
+               }
+
+               if (!pResp) {
+                       err("No <stat> in +CGREG");
+                       goto OUT;
+               }
+
+               stat = atoi(pResp);
+               __handle_ps_network_status(co, stat);
+       } else {
+               err("RESPONSE NOK");
+       }
+OUT:
+       tcore_at_tok_free(tokens);
+}
+
+static void on_response_cs_network_status(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       CoreObject *co = NULL;
+       GSList *tokens = NULL;
+       const char *line;
+       int stat = 0;
+       guint token_count = 0;
+       char *pResp = NULL;
+
+       dbg("Enter");
+
+       co = tcore_pending_ref_core_object(p);
+       if (!co) {
+               err("Failed to get CoreObject");
+               return;
+       }
+
+       if (resp && resp->success) {
+               dbg("RESPONSE OK");
+               if (1 != g_slist_length(resp->lines)) {
+                       dbg("unsolicited msg but multiple line");
+                       goto OUT;
+               }
+
+               line = (const char *) resp->lines->data;
+               tokens = tcore_at_tok_new(line);
+               token_count = g_slist_length(tokens);
+               dbg("CREG token count: %d", token_count);
+
+               if (token_count == 2 || token_count == 4) {
+                       /* Handle CREG query response */
+                       pResp = g_slist_nth_data(tokens, 1);
+               } else {
+                       err("Invalid message");
+                       goto OUT;
+               }
+
+               if (!pResp) {
+                       err("No <stat> in +CREG");
+                       goto OUT;
+               }
+
+               stat = atoi(pResp);
+               __handle_cs_network_status(co, stat);
+       } else {
+               err("RESPONSE NOK");
+       }
+OUT:
+       tcore_at_tok_free(tokens);
+}
+
+static void __handle_ps_network_status(CoreObject *co, int stat)
+{
+       enum telephony_network_service_domain_status cs_status;
+       enum telephony_network_service_domain_status ps_status, prev_status;
+       struct network_reg_status_cb_data *reg_status = NULL;
+
+       if (!co) {
+               err("CoreObject is NULL");
+               return;
+       }
+
+       dbg("stat[%d]", stat);
+       if (stat < 0 || stat > 5) {
+               err("Invalid <stat> value");
+               return;
+       }
+
+       if (stat == 5)
+               tcore_network_set_roaming_state(co, TRUE);
+       else
+               tcore_network_set_roaming_state(co, FALSE);
+
+       ps_status = __mapping_network_status(stat);
+
+       tcore_network_get_service_status(co,
+               TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET,
+               &prev_status);
+       dbg(" previous ps_status [%d],  current ps_status [%d]",
+               prev_status, ps_status);
+
+       if (ps_status != prev_status) {
+
+               tcore_network_get_service_status(co,
+                       TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT,
+                       &cs_status);
+
+               /* Callback data */
+               reg_status = g_malloc0(sizeof(struct network_reg_status_cb_data));
+               reg_status->regist_status.cs_domain_status = cs_status;
+               reg_status->regist_status.ps_domain_status = ps_status;
+               reg_status->regist_status.roaming_status
+                                                               = tcore_network_get_roaming_state(co);
+
+               /* Set PS online state */
+               __ps_set(tcore_object_ref_plugin(co), ps_status);
+
+               /* Set PS status */
+               tcore_network_set_service_status(co,
+                       TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET,
+                       ps_status);
+
+               /* Get AcT */
+               __get_act_information(co, reg_status);
+       }
+}
+
+static void __handle_cs_network_status(CoreObject *co, int stat)
+{
+       enum telephony_network_service_domain_status cs_status, prev_status;
+       enum telephony_network_service_domain_status ps_status;
+       struct network_reg_status_cb_data *reg_status = NULL;
+
+       if (!co) {
+               err("CoreObject is NULL");
+               return;
+       }
+
+       dbg("stat[%d]", stat);
+       if (stat < 0 || stat > 5) {
+               err("Invalid <stat> value");
+               return;
+       }
+
+       if (stat == 5)
+               tcore_network_set_roaming_state(co, TRUE);
+       else
+               tcore_network_set_roaming_state(co, FALSE);
+
+       cs_status = __mapping_network_status(stat);
+
+       tcore_network_get_service_status(co,
+               TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT,
+               &prev_status);
+       dbg("previous cs_status[%d], current cs_status [%d] ",
+               prev_status, cs_status);
+
+       if (cs_status != prev_status) {
+
+               if (cs_status == NETWORK_SERVICE_DOMAIN_STATUS_FULL) {
+                       /* Get Previous PS status */
+                       tcore_network_get_service_status(co,
+                               TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET,
+                               &ps_status);
+               } else {
+                       /* When CS is detached or detaching state,
+                        * PS will also be in same state */
+                       ps_status = NETWORK_SERVICE_DOMAIN_STATUS_NO;
+               }
+               dbg("ps_status [%d]", ps_status);
+               /* Callback data */
+               reg_status = g_malloc0(sizeof(struct network_reg_status_cb_data));
+               reg_status->regist_status.cs_domain_status = cs_status;
+               reg_status->regist_status.ps_domain_status = ps_status;
+               reg_status->regist_status.roaming_status
+                                                               = tcore_network_get_roaming_state(co);
+
+               /* Set current CS status*/
+               tcore_network_set_service_status(co,
+                       TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT,
+                       cs_status);
+
+               /* Get AcT */
+               __get_act_information(co, reg_status);
+       }
+}
+
+static void __send_request(CoreObject *co, const gchar *at_cmd,
+       TcorePendingResponseCallback resp_cb, void *resp_cb_data)
+{
+       tcore_prepare_and_send_at_request(co,
+               at_cmd, NULL,
+               TCORE_AT_NO_RESULT,
+               NULL,
+               resp_cb, resp_cb_data,
+               NULL, NULL,
+               0, NULL, NULL);
+}
+
+static gboolean __get_rssi_signal_cb(gpointer data)
+{
+       TReturn ret;
+       CoreObject *co_network = (CoreObject*)data;
+
+       ret = tcore_prepare_and_send_at_request(co_network,
+                       "AT+CSQ", "+CSQ",
+                       TCORE_AT_SINGLELINE,
+                       NULL,
+                       __on_response_rssi_info, NULL,
+                       NULL, NULL,
+                       0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+
+       /* Request rssi signal strength periodically */
+       /* Return FALSE to stop cycle */
+       return TRUE;
+}
+
+static void on_response_network_subscribe_events(TcorePending *p,
+       int data_len, const void *data,
+       void *user_data)
+{
+       CoreObject *co;
+       PrivateObject *po;
+       const TcoreATResponse *at_resp = data;
+       co = tcore_pending_ref_core_object(p);
+
+       if (at_resp && at_resp->success) {
+               dbg("[Last] Subscription for '%s' - [OK]", (char *)user_data);
+               po = tcore_object_ref_user_data(co);
+               if (po) {
+                       if (g_strcmp0((char *)user_data, "AT+CGREG=2") == 0)
+                               po->subscribe_cgreg_event = TRUE;
+                       else if (g_strcmp0((char *)user_data, "AT+CREG=1") == 0)
+                               po->subscribe_creg_event = TRUE;
+
+                       dbg("subscribe_creg_event[%d], subscribe_cgreg_event[%d]",
+                               po->subscribe_creg_event, po->subscribe_cgreg_event);
+               }
+
+       } else {
+               err("[Last] Subscription for '%s' - [NOK]", (char *)user_data);
+       }
+
+       /* Free resource */
+       g_free(user_data);
+}
+
+static void on_response_network_registration(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+
+       if (resp && resp->success > 0)
+               dbg("Response OK");
+       else
+               err("Response NOK");
+}
+
+static enum tcore_hook_return on_hook_sim_init(Server *s, CoreObject *source,
+       enum tcore_notification_command command,
+       unsigned int data_len, void *data, void *user_data)
+{
+       TcorePlugin *plugin = (TcorePlugin *)user_data;
+       CoreObject *co_network;
+       PrivateObject *po;
+       const struct tnoti_sim_status *sim = data;
+
+       dbg("Enter");
+
+       if (plugin == NULL) {
+               err("Invalid plugin !");
+               return TCORE_HOOK_RETURN_CONTINUE;
+       }
+
+       /*
+        * Before SIM card successfully init,
+        * +CGREG / +CREG returns error
+        *    [+CME ERROR: SIM failure]
+        * If SIM locked, it returns error
+        *    [+CME ERROR: SIM PIN required]
+        */
+       /* URC Subscriptions */
+       /* Whether sim is locked or not, it should be subscribed. */
+       /* when it is subscribed successfully, it doesn't need anymore */
+       co_network = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_NETWORK);
+       po = tcore_object_ref_user_data(co_network);
+       if (po) {
+               if (po->subscribe_cgreg_event == FALSE) {
+                       __send_request(co_network, "AT+CGREG=2",
+                               on_response_network_subscribe_events,
+                               g_strdup("AT+CGREG=2"));
+               }
+
+               if (po->subscribe_creg_event == FALSE) {
+                       __send_request(co_network, "AT+CREG=1",
+                               on_response_network_subscribe_events,
+                               g_strdup("AT+CREG=1"));
+               }
+       }
+
+       tcore_prepare_and_send_at_request(co_network,
+               "AT+CREG?", "+CREG:",
+               TCORE_AT_SINGLELINE,
+               NULL,
+               on_response_cs_network_status, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+
+       tcore_prepare_and_send_at_request(co_network,
+               "AT+CGREG?", "+CGREG:",
+               TCORE_AT_SINGLELINE,
+               NULL,
+               on_response_ps_network_status, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+
+       if (sim->sim_status == SIM_STATUS_INIT_COMPLETED) {
+               /* Sending AT+COPS */
+               tcore_prepare_and_send_at_request(co_network,
+                       "AT+COPS=0", NULL,
+                       TCORE_AT_NO_RESULT,
+                       NULL,
+                       on_response_network_registration, NULL,
+                       NULL, NULL,
+                       0, NULL, NULL);
+
+               /* Fetch RSSI */
+               po->rssi_src_id = g_timeout_add_seconds(RSSI_POLLING_TIMEOUT,
+                       __get_rssi_signal_cb, co_network);
+       }
+
+       dbg("Exit");
+       return TCORE_HOOK_RETURN_CONTINUE;
+}
+
+static void on_response_get_serving_network(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       UserRequest *ur;
+       struct tresp_network_get_serving_network serv_nw_resp = {0};
+       char *long_plmn_name = NULL;
+       char *short_plmn_name = NULL;
+       char *plmn_id = NULL;
+       CoreObject *co;
+       GSList *tokens = NULL;
+       const char *line;
+       int network_mode = -1;
+       int plmn_format = -1;
+       int value = -1;
+       struct tnoti_network_identity noti;
+       char *pResp = NULL;
+       int nol, count = 0;
+
+       co = tcore_pending_ref_core_object(p);
+
+       if (resp->success <= 0) {
+               err("RESPONSE NOK");
+
+               ur = tcore_pending_ref_user_request(p);
+               if (ur) {
+                       serv_nw_resp.result = TCORE_RETURN_FAILURE;
+                       tcore_user_request_send_response(ur,
+                               TRESP_NETWORK_GET_SERVING_NETWORK,
+                               sizeof(struct tresp_network_get_serving_network),
+                               &serv_nw_resp);
+               }
+
+               return;
+       }
+
+       dbg("RESPONSE OK");
+       nol = g_slist_length(resp->lines);
+       dbg("nun of lines : %d", nol);
+
+       for (count = 0; count < nol; count++) {
+               /* parse each line */
+               line = g_slist_nth_data(resp->lines, count);
+               tokens = tcore_at_tok_new(line);
+               dbg("line %d start---------------", count);
+               /* mode */
+               if ((pResp = tcore_at_tok_nth(tokens, 0))) {
+                       dbg("mode  : %s", pResp);
+                       if (pResp)
+                               network_mode = atoi(pResp);
+               }
+
+               /* format (optional) */
+               if ((pResp = tcore_at_tok_nth(tokens, 1))) {
+                       dbg("format  : %s", pResp);
+                       if (pResp && strlen(pResp) > 0)
+                               plmn_format = atoi(pResp);
+               }
+
+               /* plmn */
+               switch (plmn_format) {
+               case 0:
+                       if ((pResp = tcore_at_tok_nth(tokens, 2))) {
+                               dbg("long PLMN  : %s", pResp);
+                               if (pResp && strlen(pResp) > 0) {
+                                       long_plmn_name =
+                                               tcore_at_tok_extract((const char *)pResp);
+
+                                       /* set network name into po */
+                                       tcore_network_set_network_name(co,
+                                       TCORE_NETWORK_NAME_TYPE_FULL, long_plmn_name);
+                               }
+                       }
+               break;
+               case 1:
+                       if ((pResp = tcore_at_tok_nth(tokens, 2))) {
+                               dbg("short PLMN  : %s", pResp);
+                               if (pResp && strlen(pResp) > 0) {
+                                       short_plmn_name =
+                                               tcore_at_tok_extract((const char *)pResp);
+
+                                       /* set network name into po */
+                                       tcore_network_set_network_name(co,
+                                               TCORE_NETWORK_NAME_TYPE_SHORT,
+                                               short_plmn_name);
+                               }
+                       }
+               break;
+               case 2:
+                       if ((pResp = tcore_at_tok_nth(tokens, 2))) {
+                               dbg("numeric : %s", pResp);
+                               if (pResp && strlen(pResp) > 0) {
+                                       plmn_id =
+                                               tcore_at_tok_extract((const char *)pResp);
+
+                                       /* set plmn id into po */
+                                       tcore_network_set_plmn(co, plmn_id);
+                               }
+                       }
+               break;
+               default:
+                       err("invalid plmn format");
+               break;
+               }
+
+               /* rat (act) */
+               if ((pResp = tcore_at_tok_nth(tokens, 3))) {
+                       dbg("AcT  : %s", pResp);
+                       if (!pResp) {
+                               err("ACT is invalid");
+                       } else {
+                               value = atoi(pResp);
+                               if (value < AT_COPS_ACT_VALUE_MAX) {
+                                       int AcT;
+                                       AcT = lookup_tbl_access_technology[value];
+                                       tcore_network_set_access_technology(co, AcT);
+                               } else {
+                                       err("AcT is invalid or missing");
+                               }
+                       }
+               }
+               /* Free resources */
+               tcore_at_tok_free(tokens);
+       }
+
+       if (plmn_id) {
+               int plmn_len = strlen(plmn_id);
+               if (plmn_len > NETWORK_MAX_PLMN_LEN)
+                       plmn_len = NETWORK_MAX_PLMN_LEN;
+               memcpy(serv_nw_resp.plmn, plmn_id, plmn_len);
+       }
+
+       tcore_network_get_access_technology(co, &(serv_nw_resp.act));
+       tcore_network_get_lac(co, &(serv_nw_resp.gsm.lac));
+
+       ur = tcore_pending_ref_user_request(p);
+       if (ur) {
+               serv_nw_resp.result = TCORE_RETURN_SUCCESS;
+               tcore_user_request_send_response(ur, TRESP_NETWORK_GET_SERVING_NETWORK,
+                       sizeof(struct tresp_network_get_serving_network), &serv_nw_resp);
+       } else {
+               TcorePlugin *plugin = NULL;
+               /* Network change noti */
+               struct tnoti_network_change network_change;
+
+               memset(&network_change, 0, sizeof(struct tnoti_network_change));
+               if (plmn_id) {
+                       int plmn_len = strlen(plmn_id);
+                       if (plmn_len > NETWORK_MAX_PLMN_LEN)
+                               plmn_len = NETWORK_MAX_PLMN_LEN;
+                       memcpy(network_change.plmn, plmn_id, plmn_len);
+               }
+
+               tcore_network_get_access_technology(co, &(network_change.act));
+               tcore_network_get_lac(co, &(network_change.gsm.lac));
+
+               plugin = tcore_pending_ref_plugin(p);
+               tcore_server_send_notification(tcore_plugin_ref_server(plugin),
+                       tcore_pending_ref_core_object(p),
+                       TNOTI_NETWORK_CHANGE,
+                       sizeof(struct tnoti_network_change),
+                       &network_change);
+
+               dbg("network_change.plmn  : %s", network_change.plmn);
+               dbg("network_change.act  : %d", network_change.act);
+               dbg("network_change.gsm.lac  : %d", network_change.gsm.lac);
+
+               if ((2 != network_mode) && (3 != network_mode)) {
+                       /* Network identity noti */
+                       memset(&noti, 0x0, sizeof(struct tnoti_network_identity));
+                       if (long_plmn_name)
+                               memcpy(noti.full_name, long_plmn_name,
+                                       MIN(32, strlen(long_plmn_name)));
+                       if (short_plmn_name)
+                               memcpy(noti.short_name, short_plmn_name,
+                                       MIN(16, strlen(short_plmn_name)));
+                       if (plmn_id) {
+                                /* plmn_id length is necessarily <= 6 */
+                               int plmn_len = strlen(plmn_id);
+                               if (plmn_len > NETWORK_MAX_PLMN_LEN)
+                                       plmn_len = NETWORK_MAX_PLMN_LEN;
+                               memcpy(noti.plmn, plmn_id, plmn_len);
+                       }
+
+                       plugin = tcore_object_ref_plugin(co);
+                       tcore_server_send_notification(tcore_plugin_ref_server(plugin),
+                                                       co, TNOTI_NETWORK_IDENTITY,
+                                                       sizeof(struct tnoti_network_identity),
+                                                       &noti);
+
+                       dbg("noti.short_name  : %s", noti.short_name);
+                       dbg("noti.full_name  : %s", noti.full_name);
+                       dbg("noti.plmn  : %s", noti.plmn);
+               }
+       }
+
+       g_free(long_plmn_name);
+       g_free(short_plmn_name);
+       g_free(plmn_id);
+       return;
+}
+
+static TReturn get_serving_network(CoreObject *co, UserRequest *ur)
+{
+       dbg("ENTER!!");
+
+       if (!co)
+               return TCORE_RETURN_EINVAL;
+
+       /* Send Request to modem */
+       tcore_prepare_and_send_at_request(co,
+               "AT+COPS=3,2;+COPS?;+COPS=3,0;+COPS?", "+COPS",
+               TCORE_AT_MULTILINE,
+               ur,
+               on_response_get_serving_network, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+
+       return TCORE_RETURN_SUCCESS;
+}
+
+static TReturn get_default_subscription(CoreObject *co, UserRequest *ur)
+{
+       struct tresp_network_get_default_subs resp_data = {0, };
+       TReturn ret = TCORE_RETURN_SUCCESS;
+
+       dbg("Enter");
+
+       /* Only supports SIM 1 */
+       resp_data.default_subs = NETWORK_DEFAULT_SUBS_SIM1;
+       resp_data.result = TCORE_RETURN_SUCCESS;
+
+       /* Send Response */
+       ret = tcore_user_request_send_response(ur,
+               TRESP_NETWORK_GET_DEFAULT_SUBSCRIPTION,
+               sizeof(struct tresp_network_get_default_subs), &resp_data);
+
+       dbg("ret: [0x%x]", ret);
+       return ret;
+}
+
+static TReturn get_default_data_subscription(CoreObject *co, UserRequest *ur)
+{
+       struct tresp_network_get_default_data_subs resp = {0,};
+       TReturn ret = TCORE_RETURN_SUCCESS;
+
+       dbg("Enter");
+
+       /* Only supports SIM 1 */
+       resp.result = TCORE_RETURN_SUCCESS;
+       resp.default_subs = NETWORK_DEFAULT_DATA_SUBS_SIM1;
+
+       /* Send Response */
+       ret = tcore_user_request_send_response(ur,
+               TRESP_NETWORK_GET_DEFAULT_DATA_SUBSCRIPTION,
+               sizeof(struct tresp_network_get_default_data_subs), &resp);
+
+       dbg("ret: [0x%x]", ret);
+       return ret;
+}
+
+static struct tcore_network_operations network_ops = {
+       .search = NULL,
+       .set_plmn_selection_mode = NULL,
+       .get_plmn_selection_mode = NULL,
+       .set_service_domain = NULL,
+       .get_service_domain = NULL,
+       .set_band = NULL,
+       .get_band = NULL,
+       .set_preferred_plmn = NULL,
+       .get_preferred_plmn = NULL,
+       .set_order = NULL,
+       .get_order = NULL,
+       .set_power_on_attach = NULL,
+       .get_power_on_attach = NULL,
+       .set_cancel_manual_search = NULL,
+       .get_serving_network = get_serving_network,
+       .set_mode = NULL,
+       .get_mode = NULL,
+       .set_neighboring_cell_info = NULL,
+       .get_neighboring_cell_info = NULL,
+       .set_default_data_subscription = NULL,
+       .get_default_data_subscription = get_default_data_subscription,
+       .set_default_subscription = NULL,
+       .get_default_subscription = get_default_subscription,
+       .set_emergency_callback_mode = NULL,
+       .set_roaming_preference = NULL,
+       .get_roaming_preference = NULL,
+       .get_subscription_info = NULL,
+       .search_ecc_rat = NULL,
+};
+
+gboolean atd_network_init(TcorePlugin *p, CoreObject *co_network)
+{
+       PrivateObject *po = NULL;
+       dbg("Enter");
+
+       po = g_malloc0(sizeof(PrivateObject));
+       tcore_object_link_user_data(co_network, po);
+
+       /* Set operations */
+       tcore_network_set_ops(co_network, &network_ops, TCORE_OPS_TYPE_CP);
+
+       /* Add Callbacks */
+       tcore_object_add_callback(co_network, "+CREG",
+               on_event_cs_network_regist, NULL);
+       tcore_object_add_callback(co_network, "+CGREG",
+               on_event_ps_network_regist, NULL);
+
+       /* Wait for sim init */
+       tcore_server_add_notification_hook(tcore_plugin_ref_server(p),
+                               TNOTI_SIM_STATUS, on_hook_sim_init, p);
+
+       /* Set CS and PS service status to invalid */
+       tcore_network_set_service_status(co_network,
+               TCORE_NETWORK_SERVICE_DOMAIN_TYPE_CIRCUIT,
+               -1);
+       tcore_network_set_service_status(co_network,
+               TCORE_NETWORK_SERVICE_DOMAIN_TYPE_PACKET,
+               -1);
+
+       dbg("Exit");
+       return TRUE;
+}
+
+void atd_network_exit(TcorePlugin *p, CoreObject *co_network)
+{
+       Server *s;
+       PrivateObject *po;
+
+       dbg("Enter");
+
+       s = tcore_plugin_ref_server(p);
+       tcore_server_remove_notification_hook(s, on_hook_sim_init);
+
+       tcore_object_del_callback(co_network,
+               "+CREG", on_event_cs_network_regist);
+
+       tcore_object_del_callback(co_network,
+               "+CGREG", on_event_ps_network_regist);
+
+       po = tcore_object_ref_user_data(co_network);
+       if (po && po->rssi_src_id)
+               g_source_remove(po->rssi_src_id);
+
+       g_free(po);
+
+       /* Unset 'ops' */
+       tcore_network_set_ops(co_network, NULL, TCORE_OPS_TYPE_CP);
+
+       dbg("Exit");
+}
diff --git a/src/atd_ps.c b/src/atd_ps.c
new file mode 100644 (file)
index 0000000..79a1fa0
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <tcore.h>
+#include <hal.h>
+#include <core_object.h>
+#include <plugin.h>
+#include <queue.h>
+#include <co_ps.h>
+#include <co_context.h>
+#include <storage.h>
+#include <server.h>
+#include <at.h>
+#include <util.h>
+#include <type/ps.h>
+#include <vconf/vconf.h>
+
+#include "atd_ps.h"
+
+/**< DNS related */
+#define PPP_RESOLV_CONF_FILE   "/opt/etc/ppp/resolv.conf"
+#define DNS_ADDR_MAX                   2
+#define DNS_BUF_LEN                            100
+
+enum ps_data_call_status {
+       PS_DATA_CALL_CTX_DEFINED,
+       PS_DATA_CALL_CONNECTED,
+       PS_DATA_CALL_NOT_CONNECTED = 3
+};
+
+static gboolean __get_pdp_address(CoreObject *co_ps, CoreObject *ps_context,
+       const char *netif_name);
+
+static void __notify_context_status_changed(CoreObject *co_ps,
+       CoreObject *ps_context, enum ps_data_call_status state)
+{
+       struct tnoti_ps_call_status data_resp = {0, };
+       TcorePlugin *plugin = NULL;
+       Server *server = NULL;
+       Storage *strg = NULL;
+       gboolean result = FALSE;
+       dbg("Enter");
+
+       plugin = tcore_object_ref_plugin(co_ps);
+       server = tcore_plugin_ref_server(plugin);
+       strg = (Storage *)tcore_server_find_storage(server, "vconf");
+
+       data_resp.context_id = tcore_context_get_id(ps_context);
+       data_resp.state = state;
+       dbg("Sending Call Status Notification " \
+               "- Context ID: [%d], Context State: [%d]",
+               data_resp.context_id, state);
+
+       /* Update packet service state */
+       if (strg) {
+               dbg("Updating packet service state");
+               if (state == PS_DATA_CALL_CONNECTED) {
+                       result = tcore_storage_set_int(strg,
+                               STORAGE_KEY_PACKET_SERVICE_STATE,
+                               VCONFKEY_DNET_NORMAL_CONNECTED);
+               } else {
+                       result = tcore_storage_set_int(strg,
+                               STORAGE_KEY_PACKET_SERVICE_STATE,
+                               VCONFKEY_DNET_OFF);
+               }
+
+               if (!result)
+                       err("Failed to update PS state vconf key!");
+       } else {
+               err("Failed to get Storage !");
+       }
+
+       /* Send CALL Status Notification */
+       tcore_server_send_notification(server, co_ps, TNOTI_PS_CALL_STATUS,
+                               sizeof(data_resp), &data_resp);
+}
+
+static void __on_setup_pdp(CoreObject *co_ps, int result,
+       const char *netif_name, void *user_data)
+{
+       CoreObject *ps_context = user_data;
+       if (result < 0) {
+               /* Deactivate PDP context */
+               err("setup pdp failed");
+               goto OUT;
+       }
+       dbg("Device name: [%s]", netif_name);
+
+       /* Get IP address, netmask and DNS IP address */
+       if (__get_pdp_address(co_ps, ps_context, netif_name)) {
+               dbg("Get PDP address is success");
+               return;
+       }
+
+OUT:
+       /* Deactivate PDP context */
+       tcore_ps_deactivate_context(co_ps, ps_context, NULL);
+       __notify_context_status_changed(co_ps, ps_context,
+               PS_DATA_CALL_NOT_CONNECTED);
+}
+
+static void __on_deactivate_pdp(CoreObject *co_ps, int result,
+       const char *netif_name, void *user_data)
+{
+       CoreObject *ps_context = user_data;
+       dbg("Device name: [%s]", netif_name);
+
+       /* Send status notification */
+       __notify_context_status_changed(co_ps, ps_context,
+               PS_DATA_CALL_NOT_CONNECTED);
+}
+
+static void  __convert_ipv4_atoi(unsigned char *ip4, const char *str)
+{
+       char *token = NULL;
+       char *temp = NULL;
+       char *ptr = NULL;
+       int local_index = 0;
+
+       temp = g_strdup(str);
+       if (temp == NULL) {
+               err("Failed to duplicate string.");
+               return;
+       }
+
+       token = strtok_r(temp, ".", &ptr);
+       while (token != NULL) {
+               ip4[local_index++] = atoi(token);
+               msg("   [%d]", ip4[local_index-1]);
+               token = strtok_r(NULL, ".", &ptr);
+       }
+       g_free(temp);
+}
+
+static gboolean __get_pdp_address(CoreObject *co_ps, CoreObject *ps_context,
+       const char *netif_name)
+{
+       struct ifreq ifr;
+       int fd;
+       FILE *fp = NULL;
+       char buff[DNS_BUF_LEN] = "";
+       char *tmp = NULL;
+       struct in_addr in;
+       int len = 0;
+       int i = 0;
+       char *ipaddr = NULL;
+       char *net_mask = NULL;
+       struct tnoti_ps_pdp_ipconfiguration data_call_conf = {0, };
+       TcorePlugin *plugin = NULL;
+
+       dbg("Enter");
+
+       /* Socket to fetch IP address */
+       /* Type of address to retrieve - IPv4 IP address */
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (fd < 0) {
+               err("fd is negative value");
+               return FALSE;
+       }
+       /* Copy the interface name in the ifreq structure */
+       ifr.ifr_addr.sa_family = AF_INET;
+       strncpy(ifr.ifr_name, netif_name, IFNAMSIZ-1);
+
+       /* IOCTL call - Fetch IP address */
+       if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
+               dbg("Unable to fetch IP address");
+               close(fd);
+               return  FALSE;
+       }
+       /* IPv4 uses sockaddr_in,
+        * But socket library uses general structure - sockaddr */
+       ipaddr = inet_ntoa(((struct sockaddr_in *)((void *)&ifr.ifr_addr))->sin_addr);
+       dbg("IP address - interface (%s): [%s]", netif_name, ipaddr);
+        __convert_ipv4_atoi(data_call_conf.ip_address,  ipaddr);
+
+       /* IOCTL call - Fetch IP netmask */
+       ioctl(fd, SIOCGIFNETMASK, &ifr);
+       net_mask = inet_ntoa(((struct sockaddr_in *)((void *)&ifr.ifr_addr))->sin_addr);
+       dbg("Netmask: [%s]", net_mask);
+       __convert_ipv4_atoi(data_call_conf.subnet_mask, net_mask);
+
+       close(fd);
+
+       /* Provide gateway address same as IP address */
+       memcpy(data_call_conf.gateway, data_call_conf.ip_address, 4);
+
+       dbg("Gateway address in hex");
+       tcore_util_hex_dump("  ", 4, data_call_conf.gateway);
+
+       /* Get DNS address */
+       /* Use dynamically configured DNS server address */
+       if ((fp = fopen(PPP_RESOLV_CONF_FILE, "r")) == NULL) {
+               err("Failed to open resolve.conf file.. setting DNS to 'default'");
+               /* Set Primary & Secondary DNS to default*/
+               __convert_ipv4_atoi(data_call_conf.primary_dns, "8.8.8.8");
+               __convert_ipv4_atoi(data_call_conf.secondary_dns, "8.8.4.4");
+       } else {
+
+               /* Fetch DNS info from /opt/etc/ppp/resolv.conf file */
+               while (fgets(buff, DNS_BUF_LEN, fp) != NULL) {
+                       if ((tmp = strstr(buff, "nameserver")) == NULL) {
+                               memset(buff, 0, DNS_BUF_LEN);
+                               continue;
+                       } else {
+                               tmp = tmp + sizeof("nameserver");
+                               while (*tmp == ' ')
+                                       tmp++;
+                       }
+
+                       /* remove trailing '\n' */
+                       len = strlen(buff);
+                       buff[len - 1] = '\0';
+                       if (!inet_aton(tmp, &in)) {
+                               err("Configured with invalid dns address[%s]\n", tmp);
+                               fclose(fp);
+                               return FALSE;
+                       }
+
+                       if (i < DNS_ADDR_MAX) {
+                               dbg("[%d] - DNS server address is [%s]\n", i+1, inet_ntoa(in));
+                               i++;
+                       } else  /* If configured with more DNS server address just break? */
+                               break;
+
+                       if (i == 1) {
+                               /* Set primary DNS */
+                               __convert_ipv4_atoi(data_call_conf.primary_dns,
+                                       inet_ntoa(in));
+                       } else {
+                               /* Set Secondary DNS */
+                               __convert_ipv4_atoi(data_call_conf.secondary_dns,
+                                       inet_ntoa(in));
+                       }
+
+                       memset(buff, 0, DNS_BUF_LEN);
+               }
+               fclose(fp);
+       }
+
+       data_call_conf.context_id = (int)tcore_context_get_id(ps_context);
+       g_strlcpy(data_call_conf.devname, netif_name,
+                       sizeof(data_call_conf.devname) + 1);
+
+       dbg("data_call_conf.context_id[%d], data_call_conf.devname[%s]",
+               data_call_conf.context_id,
+               data_call_conf.devname);
+
+       /* Send  IP configuaration notification*/
+       plugin = tcore_object_ref_plugin(co_ps);
+       tcore_server_send_notification(tcore_plugin_ref_server(plugin),
+                                       co_ps,
+                                       TNOTI_PS_PDP_IPCONFIGURATION,
+                                       sizeof(struct tnoti_ps_pdp_ipconfiguration),
+                                       &data_call_conf);
+
+       __notify_context_status_changed(co_ps, ps_context, PS_DATA_CALL_CONNECTED);
+       return TRUE;
+}
+
+static void on_response_define_pdp_context(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       CoreObject *ps_context = (CoreObject *)user_data;
+       CoreObject *co_ps = tcore_pending_ref_core_object(p);
+       enum ps_data_call_status status;
+       dbg("Enter");
+
+       if (resp && resp->success) {
+               dbg("Response OK");
+
+               status  = PS_DATA_CALL_CTX_DEFINED;
+       } else {
+               err("Response NOK");
+               status =  PS_DATA_CALL_NOT_CONNECTED;
+       }
+
+       __notify_context_status_changed(co_ps, ps_context, status);
+}
+
+static TReturn atd_define_pdp_context(CoreObject *co_ps, CoreObject *ps_context,
+       void *user_data)
+{
+       char *apn = NULL;
+       char *cmd_str = NULL;
+       char *pdp_type_str = NULL;
+       unsigned int cid;
+       enum co_context_type pdp_type;
+       gboolean  d_comp = 1;
+       gboolean h_comp = 1;
+       TReturn ret = TCORE_RETURN_FAILURE;
+       dbg("Enter");
+
+       pdp_type = tcore_context_get_type(ps_context);
+       switch (pdp_type) {
+       case CONTEXT_TYPE_IPV4V6:
+       case CONTEXT_TYPE_IP: {
+               dbg("CONTEXT_TYPE_IP");
+               pdp_type_str = g_strdup_printf("IP");
+       }
+       break;
+
+       case CONTEXT_TYPE_PPP: {
+               dbg("CONTEXT_TYPE_PPP");
+               pdp_type_str = g_strdup_printf("PPP");
+       }
+       break;
+
+       case CONTEXT_TYPE_IPV6: {
+               dbg("CONTEXT_TYPE_IPV6");
+               pdp_type_str = g_strdup_printf("IPV6");
+       }
+       break;
+
+       default: {
+               /* PDP Type not supported supported */
+               err("Unsupported PDP type: %d returning", pdp_type);
+               return TCORE_RETURN_FAILURE;
+       }
+       }
+
+       cid = tcore_context_get_id(ps_context);
+       apn = tcore_context_get_apn(ps_context);
+
+       if (tcore_context_get_data_compression(ps_context) == CONTEXT_D_COMP_OFF)
+               d_comp = 0;
+
+       if (tcore_context_get_header_compression(ps_context) == CONTEXT_H_COMP_OFF)
+               h_comp = 0;
+
+       dbg("Define PDP context for CID[%d]", cid);
+       dbg("  pdp_type : [%s]", pdp_type_str);
+       dbg("  apn      : [%s]", apn);
+       dbg("  comp     : [%d, %d]", d_comp, h_comp);
+
+       cmd_str = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d",
+                       cid, pdp_type_str, apn, d_comp, h_comp);
+
+       ret = tcore_prepare_and_send_at_request(co_ps,
+               cmd_str, NULL,
+               TCORE_AT_NO_RESULT,
+               NULL,
+               on_response_define_pdp_context, ps_context,
+               NULL, NULL,
+               0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+
+       g_free(cmd_str);
+       g_free(pdp_type_str);
+       g_free(apn);
+
+       return ret;
+}
+
+static TReturn atd_activate_pdp_context(CoreObject *co_ps, CoreObject *ps_context,
+       void *user_data)
+{
+       TReturn ret = TCORE_RETURN_FAILURE;
+       TcoreHal *hal = tcore_object_get_hal(co_ps);
+       unsigned int cid = tcore_context_get_id(ps_context);
+
+       dbg("Setting UP network for CID: [%d] context: [%p]", cid, ps_context);
+
+       /* Mount network interface */
+       ret = tcore_hal_setup_netif(hal, co_ps,
+               __on_setup_pdp, ps_context,
+               cid, TRUE);
+       if (ret != TCORE_RETURN_SUCCESS)
+               err("Setup network interface failed- ret: [0x%x]", ret);
+
+       return ret;
+}
+
+static TReturn atd_deactivate_pdp_context(CoreObject *co_ps,
+       CoreObject *ps_context, void *user_data)
+{
+       TcoreHal *hal = tcore_object_get_hal(co_ps);
+       unsigned int cid = 0;
+       TReturn ret = TCORE_RETURN_FAILURE;
+       dbg("Enter");
+
+       /* Getting Context ID from Core Object */
+       cid = tcore_context_get_id(ps_context);
+
+       /* Unmount network interface */
+       ret = tcore_hal_setup_netif(hal, co_ps,
+                       __on_deactivate_pdp, ps_context, cid, FALSE);
+       if (ret != TCORE_RETURN_SUCCESS) {
+               err("Deactivate network interface failed. ret: [0x%x]", ret);
+               __notify_context_status_changed(co_ps, ps_context,
+                       PS_DATA_CALL_NOT_CONNECTED);
+       }
+
+       return ret;
+}
+
+/**< PS operations */
+static struct tcore_ps_operations ps_ops = {
+       .define_context = atd_define_pdp_context,
+       .activate_context = atd_activate_pdp_context,
+       .deactivate_context = atd_deactivate_pdp_context,
+       .send_dormant_request = NULL,
+};
+
+/**< PS init function */
+gboolean atd_ps_init(TcorePlugin *p, CoreObject *co_ps)
+{
+       dbg("Enter");
+
+       /* Set operations */
+       tcore_ps_set_ops(co_ps, &ps_ops, TCORE_OPS_TYPE_CP);
+
+       return TRUE;
+}
+
+/**< PS exit function */
+void atd_ps_exit(TcorePlugin *p, CoreObject *co_ps)
+{
+       dbg("Enter");
+
+       /* Unset 'ops' */
+       tcore_ps_set_ops(co_ps, NULL, TCORE_OPS_TYPE_CP);
+}
diff --git a/src/atd_sim.c b/src/atd_sim.c
new file mode 100644 (file)
index 0000000..95d4aa4
--- /dev/null
@@ -0,0 +1,1390 @@
+/*
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <unistd.h>
+
+#include <tcore.h>
+#include <hal.h>
+#include <core_object.h>
+#include <plugin.h>
+#include <queue.h>
+#include <co_sim.h>
+#include <user_request.h>
+#include <server.h>
+#include <storage.h>
+#include <at.h>
+#include <ckmc/ckmc-manager.h>
+
+#include "atd_sim.h"
+
+#define SIM_PIN_INCORRRECT_PASSWORD 16
+#define MAX_SIM_RETRY_COUNT         240
+
+#define SIM_STORE_KEY "telephony_sim_imsi1"
+
+typedef enum {
+       SEC_PIN1_VERIFY,
+       SEC_PIN2_VERIFY,
+       SEC_PUK1_VERIFY,
+       SEC_PUK2_VERIFY,
+       SEC_SIM_VERIFY,
+       SEC_ADM_VERIFY,
+       SEC_PIN1_STATUS,
+       SEC_PIN2_STATUS,
+       SEC_SIM_STATUS,
+       SEC_LOCK_INFO,
+       SEC_SIM_UNKNOWN = 0xff
+} atd_sim_sec_op_e;
+
+struct atd_sim_property {
+       atd_sim_sec_op_e current_sec_op; /**< current index to read */
+       int sim_status_counter; /* sim status counter*/
+       guint sim_init_retry_src_id; /* for sim init callback function */
+       TcorePlugin *plugin;
+};
+
+static void __sim_status_update(CoreObject *co_sim,
+       enum tel_sim_status sim_status);
+static void on_response_get_lock_info(TcorePending *p,
+       int data_len, const void *data, void *user_data);
+
+static enum tcore_response_command __find_resp_command(UserRequest *ur)
+{
+       enum tcore_request_command command;
+
+       command = tcore_user_request_get_command(ur);
+       switch (command) {
+       case TREQ_SIM_VERIFY_PINS:
+               return TRESP_SIM_VERIFY_PINS;
+
+       case TREQ_SIM_VERIFY_PUKS:
+               return TRESP_SIM_VERIFY_PUKS;
+
+       case TREQ_SIM_CHANGE_PINS:
+               return TRESP_SIM_CHANGE_PINS;
+
+       case TREQ_SIM_GET_FACILITY_STATUS:
+               return TRESP_SIM_GET_FACILITY_STATUS;
+
+       case TREQ_SIM_DISABLE_FACILITY:
+               return TRESP_SIM_DISABLE_FACILITY;
+
+       case TREQ_SIM_ENABLE_FACILITY:
+               return TRESP_SIM_ENABLE_FACILITY;
+
+       case TREQ_SIM_GET_LOCK_INFO:
+               return TRESP_SIM_GET_LOCK_INFO;
+
+       case TREQ_SIM_TRANSMIT_APDU:
+               return TRESP_SIM_TRANSMIT_APDU;
+
+       case TREQ_SIM_GET_ATR:
+               return TRESP_SIM_GET_ATR;
+
+       case TREQ_SIM_GET_ECC:
+               return TRESP_SIM_GET_ECC;
+
+       case TREQ_SIM_GET_LANGUAGE:
+               return TRESP_SIM_GET_LANGUAGE;
+
+       case TREQ_SIM_SET_LANGUAGE:
+               return TRESP_SIM_SET_LANGUAGE;
+
+       case TREQ_SIM_GET_ICCID:
+               return TRESP_SIM_GET_ICCID;
+
+       case TREQ_SIM_GET_MAILBOX:
+               return TRESP_SIM_GET_MAILBOX;
+
+       case TREQ_SIM_GET_CALLFORWARDING:
+               return TRESP_SIM_GET_CALLFORWARDING;
+
+       case TREQ_SIM_SET_CALLFORWARDING:
+               return TRESP_SIM_SET_CALLFORWARDING;
+
+       case TREQ_SIM_GET_MESSAGEWAITING:
+               return TRESP_SIM_GET_MESSAGEWAITING;
+
+       case TREQ_SIM_GET_CPHS_INFO:
+               return TRESP_SIM_GET_CPHS_INFO;
+
+       case TREQ_SIM_GET_MSISDN:
+               return TRESP_SIM_GET_MSISDN;
+
+       case TREQ_SIM_GET_SPN:
+               return TRESP_SIM_GET_SPN;
+
+       case TREQ_SIM_GET_SPDI:
+               return TRESP_SIM_GET_SPDI;
+
+       case TREQ_SIM_GET_OPL:
+               return TRESP_SIM_GET_OPL;
+
+       case TREQ_SIM_GET_PNN:
+               return TRESP_SIM_GET_PNN;
+
+       case TREQ_SIM_GET_CPHS_NETNAME:
+               return TRESP_SIM_GET_CPHS_NETNAME;
+
+       case TREQ_SIM_GET_OPLMNWACT:
+               return TRESP_SIM_GET_OPLMNWACT;
+
+       case TREQ_SIM_REQ_AUTHENTICATION:
+               return TRESP_SIM_REQ_AUTHENTICATION;
+
+       default:
+               break;
+       }
+
+       return TRESP_UNKNOWN;
+}
+
+static void __sim_status_update(CoreObject *co_sim,
+       enum tel_sim_status sim_status)
+{
+       if (sim_status != tcore_sim_get_status(co_sim)) {
+               TcorePlugin *plugin = tcore_object_ref_plugin(co_sim);
+               struct tnoti_sim_status noti_data = {0, };
+               dbg("Change in SIM State - Old State: [0x%02x] New State: [0x%02x]",
+                               tcore_sim_get_status(co_sim), sim_status);
+
+               /* Update SIM Status */
+               tcore_sim_set_status(co_sim, sim_status);
+               noti_data.sim_status = sim_status;
+
+               /* Send notification */
+               tcore_server_send_notification(tcore_plugin_ref_server(plugin),
+                               co_sim, TNOTI_SIM_STATUS,
+                               sizeof(noti_data), &noti_data);
+       }
+}
+
+static char *_add_shared_owner_prefix(const char *name)
+{
+       size_t alias_len = strlen(name) + strlen(ckmc_owner_id_system) + strlen(ckmc_owner_id_separator);
+       char *ckm_alias = (char *)malloc(alias_len + 1);
+       if (!ckm_alias) {
+               err("Failed to allocate memory");
+               return NULL;
+       }
+       memset(ckm_alias, 0, alias_len);
+       strncat(ckm_alias, ckmc_owner_id_system, strlen(ckmc_owner_id_system));
+       strncat(ckm_alias, ckmc_owner_id_separator, strlen(ckmc_owner_id_separator));
+       strncat(ckm_alias, name, strlen(name));
+
+       return ckm_alias;
+}
+
+static gboolean __sim_check_identity(CoreObject *co_sim,
+       struct tel_sim_imsi *imsi)
+{
+       gboolean is_changed = TRUE;
+       /* IMSI is 15 digit, but for distingushing between plmn and msin,
+        * define as 16 bytes. */
+       char new_imsi[16 + 1];
+       char *imsi_buf = NULL;
+       int ret_val = 0;
+       int ret = 0;
+
+       char *alias = NULL;
+       char *passwd = NULL;
+       ckmc_raw_buffer_s *ckmc_buffer;
+
+       dbg("Entry");
+       if (NULL == imsi) {
+               err("imsi is NULL");
+               return FALSE;
+       }
+
+       alias = _add_shared_owner_prefix(SIM_STORE_KEY);
+       if (alias == NULL) {
+               err("Failed to allocate alias name.");
+               return FALSE;
+       }
+
+       memset(new_imsi, 0x5F, 16);
+       memcpy(new_imsi, imsi->plmn, strlen(imsi->plmn));
+       memcpy(&new_imsi[6], imsi->msin, strlen(imsi->msin));
+       new_imsi[6 + strlen(imsi->msin)] = '\0';
+
+       ret_val = ckmc_get_data(alias, passwd, &ckmc_buffer);
+       if (ret_val == CKMC_ERROR_DB_ALIAS_UNKNOWN)
+               is_changed = TRUE;
+       else if (ret_val != CKMC_ERROR_NONE)
+               warn("ckmc_get_data failed. ret_val=[%d]", ret_val);
+       else
+               imsi_buf = (char*)ckmc_buffer->data;
+
+       if (ret_val == CKMC_ERROR_NONE && imsi_buf != NULL) {
+               if (strncmp(imsi_buf, new_imsi, 16) == 0) {
+                       is_changed = FALSE;
+                       dbg("Same sim");
+               } else {
+                       dbg("Remove previous data");
+                       ret = ckmc_remove_alias(alias);
+                       if (CKMC_ERROR_NONE != ret)
+                               warn("ckmc_remove_alias failed. ret=[%d]", ret);
+               }
+               ckmc_buffer_free(ckmc_buffer);
+       }
+
+       if (is_changed) {
+               ckmc_policy_s policy;
+               ckmc_raw_buffer_s store_buffer;
+
+               policy.password = passwd;
+               policy.extractable = true;
+               store_buffer.data = (unsigned char*)new_imsi;
+               store_buffer.size = strlen(new_imsi) + 1;
+
+               dbg("NEW SIM");
+               /* Update file */
+               ret_val = ckmc_save_data(alias, store_buffer, policy);
+               if (ret_val != CKMC_ERROR_NONE)
+                       err("ckmc_save_data failed. ret_val=[%d]", ret_val);
+       }
+
+       /* Update sim identification */
+       tcore_sim_set_identification(co_sim, is_changed);
+
+       if (alias)
+               free(alias);
+
+       return TRUE;
+}
+
+static gboolean __sim_timer_handler_cb(gpointer data)
+{
+       struct atd_sim_property *sp = data;
+
+       dbg("Entry");
+       if (!sp) {
+               err("invalid user data");
+               return FALSE;
+       }
+
+       get_sim_status(sp->plugin);
+       sp->sim_init_retry_src_id = 0;
+
+       /* return FALSE to stop cycle */
+       return FALSE;
+}
+
+static void on_response_get_imsi(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       GSList *tokens = NULL;
+       const char *line;
+       const char *imsi_str;
+       const char *error_str;
+       CoreObject *co_sim = NULL;
+       TcorePlugin *plugin = NULL;
+       struct tel_sim_imsi *imsi = NULL;
+
+       co_sim = tcore_pending_ref_core_object(p);
+       if (co_sim == NULL) {
+               err("CoreObject is NULL");
+               return;
+       }
+
+       if (resp && resp->success) {
+               dbg("RESPONSE OK");
+               if (resp->lines) {
+                       int plmn_digits = 5;
+                       char *plmn = NULL;
+
+                       line = (const char *) resp->lines->data;
+                       dbg("Line : [%s]", line);
+                       tokens = tcore_at_tok_new(line);
+                       if (g_slist_length(tokens) != 1) {
+                               err("invalid message.");
+                               goto OUT;
+                       }
+
+                       /* Copy IMSI */
+                       imsi = g_try_new0(struct tel_sim_imsi, 1);
+                       if (imsi == NULL) {
+                               err("IMSI allocation failed.");
+                               goto OUT;
+                       }
+
+                       imsi_str = g_slist_nth_data(tokens, 0);
+
+                       /* Determine # of PLMN digits (5 or 6) */
+                       plmn = g_strndup(imsi_str, 6 + 1);
+                       if (plmn) {
+                               plmn[6] = '\0';
+                               if (tcore_sim_check_plmn_having_3digits_mnc(plmn))
+                                       plmn_digits = 6;
+
+                               g_free(plmn);
+                       }
+
+                       memcpy(imsi->plmn, imsi_str, plmn_digits);
+                       imsi->plmn[plmn_digits] = '\0';
+                       memcpy(imsi->msin, imsi_str+plmn_digits,
+                                       strlen(imsi_str) - plmn_digits);
+                       imsi->msin[strlen(imsi_str) - plmn_digits] = '\0';
+                       dbg("imsi len[%d], imsi->plmn[%s], imsi->msin[%s]",
+                                       strlen(imsi_str), imsi->plmn, imsi->msin);
+
+                       __sim_check_identity(co_sim, imsi);
+                       tcore_sim_set_imsi(co_sim, imsi);
+
+                       /* Update status */
+                       __sim_status_update(co_sim, SIM_STATUS_INIT_COMPLETED);
+               }
+       } else {
+               err("RESPONSE NOK");
+               if (!resp)
+                       goto OUT;
+
+               line = (const char *)resp->final_response;
+               tokens = tcore_at_tok_new(line);
+               if (g_slist_length(tokens) < 1) {
+                       err("Unknown Error OR Corrupted string");
+                       goto OUT;
+               }
+
+               error_str = g_slist_nth_data(tokens, 0);
+               dbg("Error: [%s]", error_str);
+               if (g_str_has_prefix(error_str, "SIM PIN") == FALSE
+                               && g_str_has_prefix(error_str, "SIM PUK") == FALSE)
+                       goto OUT;
+
+               /* When it is failed, we need to check sim status again */
+               plugin = tcore_object_ref_plugin(co_sim);
+               if (!plugin) {
+                       err("Failed to get plugin");
+                       goto OUT;
+               }
+               get_sim_status(plugin);
+       }
+OUT:
+       /* Free resources */
+       tcore_at_tok_free(tokens);
+}
+
+static gboolean __get_sim_type(CoreObject *co_sim)
+{
+       enum tel_sim_type sim_type = SIM_TYPE_UNKNOWN;
+
+       dbg("Entry");
+
+       /* set SIM type to USIM because there is no AT command */
+       sim_type = SIM_TYPE_USIM;
+       dbg("SIM Type is %d", sim_type);
+
+       tcore_sim_set_type(co_sim, sim_type);
+       tcore_sim_set_app_list(co_sim, SIM_APP_TYPE_USIM);
+
+       return TRUE;
+}
+
+static gboolean __get_sim_imsi(CoreObject *co_sim)
+{
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       ret = tcore_prepare_and_send_at_request(co_sim,
+               "AT+CIMI", NULL,
+               TCORE_AT_NUMERIC, NULL,
+               on_response_get_imsi, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+       if (ret != TCORE_RETURN_SUCCESS) {
+               err("ret: [0x%x]", ret);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static int __sim_get_current_pin_facility(atd_sim_sec_op_e op)
+{
+       int ret_type = 0;
+
+       dbg("current sec_op[%d]", op);
+
+       switch (op) {
+       case SEC_PIN1_VERIFY:
+               ret_type = SIM_PTYPE_PIN1;
+               break;
+
+       case SEC_PIN2_VERIFY:
+               ret_type = SIM_PTYPE_PIN2;
+               break;
+
+       case SEC_PUK1_VERIFY:
+               ret_type = SIM_PTYPE_PUK1;
+               break;
+
+       case SEC_PUK2_VERIFY:
+               ret_type = SIM_PTYPE_PUK2;
+               break;
+
+       case SEC_PIN1_STATUS:
+               ret_type = SIM_FACILITY_SC;
+               break;
+
+       case SEC_SIM_STATUS:
+               ret_type = SIM_FACILITY_PS;
+               break;
+
+       default:
+               err("not handled current sec op[%d]", op);
+               break;
+       }
+
+       return ret_type;
+}
+
+static void on_response_get_lock_info(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       UserRequest *ur = NULL;
+       CoreObject *co_sim = NULL;
+       struct atd_sim_property *sp = NULL;
+       GSList *tokens = NULL;
+
+       dbg("Entry");
+
+       co_sim = tcore_pending_ref_core_object(p);
+       sp = tcore_sim_ref_userdata(co_sim);
+       if (!sp) {
+               err("invalid user data");
+               return;
+       }
+       ur = tcore_pending_ref_user_request(p);
+
+       if (resp && resp->success > 0) {
+               const char *line = NULL;
+               char *res_type = NULL;
+
+               dbg("RESPONSE OK");
+               if (!resp->lines) {
+                       err("invalid message");
+                       return;
+               }
+
+               line = (const char *)resp->lines->data;
+               tokens = tcore_at_tok_new(line);
+
+               res_type = g_slist_nth_data(tokens, 0);
+               dbg("Lock type: [%s]", res_type);
+
+               switch (sp->current_sec_op) {
+               case SEC_LOCK_INFO: {
+                       struct tresp_sim_get_lock_info v_info = {0, };
+                       v_info.type = SIM_FACILITY_SC;
+
+                       if (g_strcmp0(res_type, "SIM PIN") == 0) {
+                               dbg("SIM PIN LOCK");
+
+                               v_info.result = SIM_PIN_OPERATION_SUCCESS;
+                               v_info.retry_count = 0;
+                               v_info.lock_status = SIM_LOCK_STATUS_PIN;
+                       } else if (g_strcmp0(res_type, "SIM PIN2") == 0) {
+                               dbg("SIM PIN2 LOCK");
+
+                               v_info.result = SIM_PIN_OPERATION_SUCCESS;
+                               v_info.retry_count = 0;
+                               v_info.lock_status = SIM_LOCK_STATUS_PIN2;
+                       } else if (g_strcmp0(res_type, "SIM PUK") == 0) {
+                               dbg("SIM PUK LOCK");
+
+                               v_info.result = SIM_PIN_OPERATION_SUCCESS;
+                               v_info.retry_count = 0;
+                               v_info.lock_status = SIM_LOCK_STATUS_PUK;
+                       } else if (g_strcmp0(res_type, "SIM PUK2") == 0) {
+                               dbg("SIM PUK2 LOCK");
+
+                               v_info.result = SIM_PIN_OPERATION_SUCCESS;
+                               v_info.retry_count = 0;
+                               v_info.lock_status = SIM_LOCK_STATUS_PUK2;
+                       } else if (g_strcmp0(res_type, "READY") == 0) {
+                               dbg("SIM IS NOT LOCKED");
+
+                               v_info.result = SIM_PIN_OPERATION_SUCCESS;
+                               v_info.retry_count = 0;
+                               v_info.lock_status = SIM_LOCK_STATUS_UNLOCKED;
+                       } else {
+                               err("UNKNOWN LOCK");
+
+                               v_info.result = SIM_CARD_ERROR;
+                               v_info.retry_count = 0;
+                               v_info.lock_status = SIM_LOCK_STATUS_PERM_BLOCKED;
+                       }
+
+                       tcore_user_request_send_response(ur, __find_resp_command(ur),
+                                sizeof(struct tresp_sim_get_lock_info), &v_info);
+               }
+               break;
+
+               default:
+                       err("not handled sec op[%d]", sp->current_sec_op);
+               break;
+               }
+
+               /* Free tokens */
+               tcore_at_tok_free(tokens);
+       }
+}
+
+static void on_response_verify_pins(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       UserRequest *ur = NULL;
+       CoreObject *co_sim = NULL;
+       const struct treq_sim_verify_pins *req_data = NULL;
+       struct tresp_sim_verify_pins res = {0,};
+
+       dbg("Entry");
+
+       co_sim = tcore_pending_ref_core_object(p);
+       ur = tcore_pending_ref_user_request(p);
+
+       res.result = SIM_CARD_ERROR;
+
+       req_data = tcore_user_request_ref_data(ur, NULL);
+       if (!req_data) {
+               err("Invalid data");
+               goto  OUT;
+       }
+
+       if (resp && resp->success > 0) {
+               struct atd_sim_property *sp = NULL;
+               dbg("RESPONSE OK");
+
+               sp = tcore_sim_ref_userdata(co_sim);
+               if (!sp) {
+                       err("invalid user data");
+                       goto OUT;
+               }
+
+               /* Get PIN facility */
+               res.pin_type = __sim_get_current_pin_facility(sp->current_sec_op);
+               res.result = SIM_PIN_OPERATION_SUCCESS;
+
+               get_sim_status(tcore_object_ref_plugin(co_sim));
+       } else {
+               GSList *tokens = NULL;
+               const char *line;
+               int err = 0;
+
+               err("RESPONSE NOK");
+               if (!resp) {
+                       err("invalid data");
+                       goto OUT;
+               }
+
+               line = (const char *)resp->final_response;
+               tokens = tcore_at_tok_new(line);
+               if (g_slist_length(tokens) < 1) {
+                       err("Unknown Error OR Corrupted string");
+                       tcore_at_tok_free(tokens);
+                       goto OUT;
+               } else {
+                       const char *check = NULL;
+                       check = g_slist_nth_data(tokens, 0);
+                       if (check)
+                               err = atoi(check);
+                       err("Error: [%d]", err);
+
+                       if (err == SIM_PIN_INCORRRECT_PASSWORD)
+                               res.result = SIM_INCORRECT_PASSWORD;
+               }
+
+               /* Free tokens */
+               tcore_at_tok_free(tokens);
+
+               return;
+       }
+
+OUT:
+       tcore_user_request_send_response(ur, __find_resp_command(ur),
+               sizeof(struct tresp_sim_verify_pins), &res);
+}
+
+static void on_response_verify_puks(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       UserRequest *ur = NULL;
+       CoreObject *co_sim = NULL;
+       const struct treq_sim_verify_puks *req_data;
+       struct tresp_sim_verify_puks res = {0,};
+
+       dbg("Entry");
+
+       co_sim = tcore_pending_ref_core_object(p);
+       ur = tcore_pending_ref_user_request(p);
+
+       res.result = SIM_CARD_ERROR;
+
+       req_data = tcore_user_request_ref_data(ur, NULL);
+       if (!req_data) {
+               err("Invalid data");
+               goto  OUT;
+       }
+
+       if (resp && resp->success > 0) {
+               struct atd_sim_property *sp = NULL;
+
+               dbg("RESPONSE OK");
+               sp = tcore_sim_ref_userdata(co_sim);
+               if (!sp) {
+                       err("invalid user data");
+                       goto OUT;
+               }
+
+               /* Get PIN facility */
+               res.pin_type = __sim_get_current_pin_facility(sp->current_sec_op);
+               res.result = SIM_PIN_OPERATION_SUCCESS;
+
+               get_sim_status(tcore_object_ref_plugin(co_sim));
+       } else {
+               GSList *tokens = NULL;
+               const char *line;
+               int err = 0;
+
+               err("RESPONSE NOK");
+               if (!resp) {
+                       err("invalid data");
+                       goto OUT;
+               }
+
+               line = (const char *)resp->final_response;
+               tokens = tcore_at_tok_new(line);
+
+               if (g_slist_length(tokens) < 1) {
+                       err("Unknown Error OR String corrupted");
+                       tcore_at_tok_free(tokens);
+                       goto OUT;
+
+               } else {
+                       const char *check = NULL;
+                       check = g_slist_nth_data(tokens, 0);
+                       if (check)
+                               err = atoi(check);
+                       err("Error: [%d]", err);
+
+                       if (err == SIM_PIN_INCORRRECT_PASSWORD)
+                               res.result = SIM_INCORRECT_PASSWORD;
+               }
+               tcore_at_tok_free(tokens);
+       }
+       return;
+OUT:
+       tcore_user_request_send_response(ur,
+               __find_resp_command(ur),
+               sizeof(struct tresp_sim_verify_puks), &res);
+}
+
+static void on_response_get_facility_status(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       struct tresp_sim_get_facility_status res = {0,};
+       UserRequest *ur = NULL;
+       GSList *tokens = NULL;
+
+       dbg("Entry");
+
+       res.type = (int)user_data;
+       res.result = SIM_INCOMPATIBLE_PIN_OPERATION;
+
+       if (resp && resp->success > 0) {
+               const char *line;
+               const char *check = NULL;
+               dbg("RESPONSE OK");
+               if (resp->lines) {
+                       line = (const char *)resp->lines->data;
+                       tokens = tcore_at_tok_new(line);
+                       if (g_slist_length(tokens) != 1) {
+                               dbg("Invalid message");
+
+                               goto OUT;
+                       }
+
+                       check = g_slist_nth_data(tokens, 0);
+                       if (check)
+                               res.b_enable = atoi(check);
+
+                       res.result = SIM_PIN_OPERATION_SUCCESS;
+               }
+
+       } else {
+               err("RESPONSE NOK");
+       }
+
+OUT:
+       /* Send Response */
+       ur = tcore_pending_ref_user_request(p);
+       if (ur) {
+               tcore_user_request_send_response(ur,
+                       __find_resp_command(ur),
+                       sizeof(struct tresp_sim_get_facility_status), &res);
+       }
+
+       tcore_at_tok_free(tokens);
+}
+
+static void on_response_enable_facility(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       UserRequest *ur = NULL;
+       CoreObject *co_sim = NULL;
+       struct atd_sim_property *sp = NULL;
+       GSList *tokens = NULL;
+       struct tresp_sim_enable_facility res;
+
+       dbg("Entry");
+
+       co_sim = tcore_pending_ref_core_object(p);
+       sp = tcore_sim_ref_userdata(co_sim);
+
+       memset(&res, 0, sizeof(struct tresp_sim_enable_facility));
+
+       res.type = (int)user_data;
+       res.result = SIM_CARD_ERROR;
+
+       if (resp && resp->success > 0) {
+               const char *line;
+               dbg("RESPONSE OK");
+               if (resp->lines) {
+                       line = (const char *)resp->lines->data;
+                       tokens = tcore_at_tok_new(line);
+
+                       if (g_slist_length(tokens) != 1) {
+                               dbg("Invalid message");
+
+                               /* Send Response */
+                               tcore_user_request_send_response(ur,
+                                       __find_resp_command(ur),
+                                       sizeof(struct tresp_sim_enable_facility), &res);
+                               tcore_at_tok_free(tokens);
+                               return;
+                       }
+               }
+
+               res.result = SIM_PIN_OPERATION_SUCCESS;
+               /* Get SIM status */
+               get_sim_status(tcore_object_ref_plugin(co_sim));
+
+               /* Free tokens */
+               tcore_at_tok_free(tokens);
+       } else {
+               dbg("RESPONSE NOK");
+       }
+
+       /* Send Response */
+       ur = tcore_pending_ref_user_request(p);
+       if (ur) {
+               tcore_user_request_send_response(ur, __find_resp_command(ur),
+                        sizeof(struct tresp_sim_enable_facility), &res);
+       }
+
+       dbg("Exit");
+}
+
+static void on_response_disable_facility(TcorePending *p, int data_len,
+       const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       UserRequest *ur = NULL;
+       CoreObject *co_sim = NULL;
+       struct atd_sim_property *sp = NULL;
+       GSList *tokens = NULL;
+       struct tresp_sim_disable_facility res;
+
+       dbg("Entry");
+
+       co_sim = tcore_pending_ref_core_object(p);
+       sp = tcore_sim_ref_userdata(co_sim);
+
+       memset(&res, 0, sizeof(struct tresp_sim_disable_facility));
+
+       res.type = (int)user_data;
+       res.result = SIM_CARD_ERROR;
+
+       if (resp && resp->success > 0) {
+               const char *line;
+               dbg("RESPONSE OK");
+               if (resp->lines) {
+                       line = (const char *)resp->lines->data;
+                       tokens = tcore_at_tok_new(line);
+
+                       if (g_slist_length(tokens) != 1) {
+                               dbg("Invalid message");
+
+                               /* Send Response */
+                               tcore_user_request_send_response(ur,
+                                       __find_resp_command(ur),
+                                       sizeof(struct tresp_sim_disable_facility), &res);
+                               tcore_at_tok_free(tokens);
+                               return;
+                       }
+               }
+
+               res.result = SIM_PIN_OPERATION_SUCCESS;
+
+               /* Free tokens */
+               tcore_at_tok_free(tokens);
+       } else {
+               dbg("RESPONSE NOK");
+       }
+
+       /* Send Response */
+       ur = tcore_pending_ref_user_request(p);
+       if (ur) {
+               tcore_user_request_send_response(ur, __find_resp_command(ur),
+                        sizeof(struct tresp_sim_disable_facility), &res);
+       }
+
+       dbg("Exit");
+}
+
+static void on_response_get_sim_status(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *resp = data;
+       GSList *tokens = NULL;
+       const char *line;
+       const char *sim_status;
+       enum tel_sim_status sim_state = SIM_STATUS_UNKNOWN;
+       CoreObject *co_sim = NULL;
+
+       TcorePlugin *plugin;
+       enum tel_sim_type sim_type = SIM_TYPE_UNKNOWN;
+       struct tel_sim_imsi *sim_imsi = NULL;
+       struct atd_sim_property *sp = NULL;
+
+       co_sim = tcore_pending_ref_core_object(p);
+       if (co_sim == NULL) {
+               err("CoreObject  is NULL");
+               goto OUT;
+       }
+       plugin = tcore_object_ref_plugin(co_sim);
+       if (plugin == NULL) {
+               err("plugin  is NULL");
+               goto OUT;
+       }
+       sp = tcore_sim_ref_userdata(co_sim);
+       if (!sp) {
+               err("invalid user data");
+               return;
+       }
+
+       if (resp && resp->success) {
+               dbg("RESPONSE OK");
+               if (resp->lines) {
+                       line = (const char *) resp->lines->data;
+                       dbg("Line : [%s]", line);
+                       tokens = tcore_at_tok_new(line);
+                       /* Response strcuture would be -
+                        *   <CR><LF>+CPIN: <code><CR><LF>
+                        *   <CR><LF>OK<CR><LF>
+                        */
+                       sim_status = g_slist_nth_data(tokens, 0);
+
+                       if (!sim_status) {
+                               err("Invalid data");
+                               goto OUT;
+                       }
+
+                       dbg("status: [%s]", sim_status);
+                       if (g_strcmp0(sim_status, "READY") == 0) {
+                               sim_state = SIM_STATUS_INIT_COMPLETED;
+                               dbg("VALID SIM STATE");
+                       } else if (g_strcmp0(sim_status, "SIM PIN") == 0) {
+                               sim_state = SIM_STATUS_PIN_REQUIRED;
+                               dbg("SIM PIN REQUIRED");
+                       } else if (g_strcmp0(sim_status, "SIM PIN2") == 0) {
+                               sim_state = SIM_STATUS_PIN_REQUIRED;
+                               dbg("SIM PIN2 REQUIRED");
+                       } else if (g_strcmp0(sim_status, "SIM PUK") == 0) {
+                               sim_state = SIM_STATUS_PUK_REQUIRED;
+                               dbg("SIM PUK REQUIRED");
+                       } else if (g_strcmp0(sim_status, "SIM PUK2") == 0) {
+                               sim_state = SIM_STATUS_PUK_REQUIRED;
+                               dbg("SIM PUK2 REQUIRED");
+                       }
+
+                       switch (sim_state) {
+                       case SIM_STATUS_INIT_COMPLETED:
+                               dbg("[SIM] SIM INIT COMPLETED");
+                               /* TODO: Check SIM type - 2G / 3G */
+                               sim_type = tcore_sim_get_type(co_sim);
+                               sim_imsi = tcore_sim_get_imsi(co_sim);
+                               if (!sim_imsi) {
+                                       err("[SIM] imsi is NULL");
+                                       goto OUT;
+                               }
+                               if (sim_type == SIM_TYPE_UNKNOWN
+                                       || strlen(sim_imsi->plmn) == 0) {
+                                       __get_sim_type(co_sim);
+                                       __get_sim_imsi(co_sim);
+                               } else {
+                                       /* Update status */
+                                       __sim_status_update(co_sim, sim_state);
+                               }
+                               sp->sim_status_counter = 0;
+                               g_free(sim_imsi);
+                               goto OUT;
+                       break;
+
+                       case SIM_STATUS_PIN_REQUIRED:
+                               dbg("SIM PIN is required !");
+                               __sim_status_update(co_sim, sim_state);
+                               goto OUT;
+                       break;
+
+                       case SIM_STATUS_PUK_REQUIRED:
+                               dbg("SIM PUK is required !");
+                               __sim_status_update(co_sim, sim_state);
+                               goto OUT;
+                       break;
+
+                       case SIM_STATUS_CARD_NOT_PRESENT:
+                               err("[SIM] SIM CARD NOT PRESENT");
+                               tcore_sim_set_type(co_sim, SIM_TYPE_UNKNOWN);
+                       break;
+
+                       case SIM_STATUS_UNKNOWN:
+                               err("[SIM] SIM CARD IS INVALID");
+                               tcore_sim_set_type(co_sim, SIM_TYPE_UNKNOWN);
+                       break;
+
+                       case SIM_STATUS_INITIALIZING:
+                               err("[SIM] SIM STATUS INITIALIZING");
+                               tcore_sim_set_type(co_sim, SIM_TYPE_UNKNOWN);
+                       break;
+                       default:
+                               err("SIM Status: [0x%02x]", sim_state);
+                       break;
+                       }
+
+                       /* Update status */
+                       __sim_status_update(co_sim, sim_state);
+                       dbg("SIM init not completed");
+                       /* Poll for 240 seconds to get SIM status*/
+                       if (sp->sim_status_counter < MAX_SIM_RETRY_COUNT) {
+                               sp->plugin = plugin;
+                               if (sp->sim_init_retry_src_id) {
+                                       dbg("Remove timer source id");
+                                       g_source_remove(sp->sim_init_retry_src_id);
+                                       sp->sim_init_retry_src_id = 0;
+                               }
+                               sp->sim_init_retry_src_id = g_timeout_add(1000,
+                                       __sim_timer_handler_cb, sp);
+
+                               sp->sim_status_counter++;
+                               dbg("counter[%d]", sp->sim_status_counter);
+                       } else  {
+                               sp->sim_status_counter = 0;
+                               err("Failed to get sim state !");
+                               err("[SIM] SIM CARD NOT PRESENT");
+                               tcore_sim_set_type(co_sim, SIM_TYPE_UNKNOWN);
+                               __sim_status_update(co_sim, SIM_STATUS_CARD_NOT_PRESENT);
+                       }
+               } else {
+                       err("has no lines !!");
+                       get_sim_status(plugin);
+               }
+       } else {
+               err("RESPONSE NOK");
+               get_sim_status(plugin);
+       }
+OUT:
+       /* Free resources */
+       tcore_at_tok_free(tokens);
+}
+
+gboolean get_sim_status(TcorePlugin *plugin)
+{
+       CoreObject *co;
+       TReturn ret;
+
+       dbg("Entry");
+       co = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SIM);
+
+       /* Get SIM status */
+       ret = tcore_prepare_and_send_at_request(co,
+               "AT+CPIN?", "+CPIN:",
+               TCORE_AT_SINGLELINE,
+               NULL,
+               on_response_get_sim_status, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+       if (ret != TCORE_RETURN_SUCCESS)
+               return FALSE;
+
+       return TRUE;
+}
+
+static TReturn atd_verify_pins(CoreObject *co_sim, UserRequest *ur)
+{
+       char *cmd_str = NULL;
+       const struct treq_sim_verify_pins *req_data = NULL;
+       struct atd_sim_property *sp = NULL;
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       if ((co_sim == NULL) || (ur == NULL)) {
+               err("co: [%p] ur: [%p]", co_sim);
+               return TCORE_RETURN_EINVAL;
+       }
+
+       sp = tcore_sim_ref_userdata(co_sim);
+       if (!sp) {
+               err("sim property is NULL");
+               return TCORE_RETURN_EINVAL;
+       }
+       req_data = tcore_user_request_ref_data(ur, NULL);
+
+       if (req_data->pin_type == SIM_PTYPE_PIN1) {
+               sp->current_sec_op = SEC_PIN1_VERIFY;
+       } else if (req_data->pin_type == SIM_PTYPE_PIN2) {
+               sp->current_sec_op = SEC_PIN2_VERIFY;
+       } else {
+               err("Invalid PIN type: [%d]", req_data->pin_type);
+               return TCORE_RETURN_EINVAL;
+       }
+
+       cmd_str = g_strdup_printf("AT+CPIN=\"%s\"", req_data->pin);
+       ret = tcore_prepare_and_send_at_request(co_sim,
+               cmd_str, NULL,
+               TCORE_AT_NO_RESULT,
+               ur,
+               on_response_verify_pins, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+       g_free(cmd_str);
+
+       return ret;
+}
+
+static TReturn atd_verify_puks(CoreObject *co_sim, UserRequest *ur)
+{
+       char *cmd_str = NULL;
+       const struct treq_sim_verify_puks *req_data;
+       struct atd_sim_property *sp = NULL;
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       if ((co_sim == NULL) || (ur == NULL)) {
+               err("co: [%p] ur: [%p]", co_sim);
+               return TCORE_RETURN_EINVAL;
+       }
+
+       sp = tcore_sim_ref_userdata(co_sim);
+       if (!sp) {
+               err("sim property is NULL");
+               return TCORE_RETURN_EINVAL;
+       }
+       req_data = tcore_user_request_ref_data(ur, NULL);
+
+       if (req_data->puk_type == SIM_PTYPE_PUK1) {
+               sp->current_sec_op = SEC_PUK1_VERIFY;
+       } else if (req_data->puk_type == SIM_PTYPE_PUK2) {
+               sp->current_sec_op = SEC_PUK2_VERIFY;
+       } else {
+               err("Invalid PUK type: [%d]", req_data->puk_type);
+               return TCORE_RETURN_EINVAL;
+       }
+
+       cmd_str = g_strdup_printf("AT+CPIN=\"%s\", \"%s\"",
+                                                               req_data->puk, req_data->pin);
+       ret = tcore_prepare_and_send_at_request(co_sim,
+               cmd_str, NULL,
+               TCORE_AT_NO_RESULT,
+               ur,
+               on_response_verify_puks, NULL,
+               NULL, NULL,
+               0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+       g_free(cmd_str);
+
+       return ret;
+}
+
+static TReturn atd_get_facility_status(CoreObject *co_sim, UserRequest *ur)
+{
+       char *cmd_str = NULL;
+       const struct treq_sim_get_facility_status *req_data;
+       int mode = 2;    /* 0:unblock, 1:lock, 2:query state */
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       if ((co_sim == NULL) || (ur == NULL)) {
+               err("co: [%p] ur: [%p]", co_sim);
+               return TCORE_RETURN_EINVAL;
+       }
+
+       req_data = tcore_user_request_ref_data(ur, NULL);
+       if (!req_data) {
+               err("invalid ref data");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       /* supports only faclity type "SC" */
+       if (req_data->type != SIM_FACILITY_SC) {
+               err("Invalid facility type");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       cmd_str = g_strdup_printf("AT+CLCK=\"SC\", %d", mode);
+       ret = tcore_prepare_and_send_at_request(co_sim,
+                       cmd_str, "+CLCK:",
+                       TCORE_AT_SINGLELINE,
+                       ur,
+                       on_response_get_facility_status, (void *)req_data->type,
+                       NULL, NULL,
+                       0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+       g_free(cmd_str);
+
+       return ret;
+}
+
+static TReturn atd_enable_facility(CoreObject *co_sim, UserRequest *ur)
+{
+       char *cmd_str = NULL;
+       const struct treq_sim_enable_facility *req_data;
+       int mode = 1;    /* 0:unlock, 1:lock, 2:query*/
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       if ((co_sim == NULL) || (ur == NULL)) {
+               err("co: [%p] ur: [%p]", co_sim);
+               return TCORE_RETURN_EINVAL;
+       }
+
+       req_data = tcore_user_request_ref_data(ur, NULL);
+       if (!req_data) {
+               err("invalid ref data");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       /* supports only faclity type "SC" */
+       if (req_data->type != SIM_FACILITY_SC) {
+               err("Invalid facility type");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       cmd_str = g_strdup_printf("AT+CLCK=\"SC\", %d, \"%s\"",
+                                       mode, req_data->password);
+
+       ret = tcore_prepare_and_send_at_request(co_sim,
+                       cmd_str, "+CLCK:",
+                       TCORE_AT_SINGLELINE,
+                       ur,
+                       on_response_enable_facility, (void *)req_data->type,
+                       NULL, NULL,
+                       0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+       g_free(cmd_str);
+
+       return ret;
+}
+
+static TReturn atd_disable_facility(CoreObject *co_sim, UserRequest *ur)
+{
+       char *cmd_str = NULL;
+       const struct treq_sim_disable_facility *req_data;
+       int mode = 0;    /* 0:unlock, 1:lock, 2:query*/
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       if ((co_sim == NULL) || (ur == NULL)) {
+               err("co: [%p] ur: [%p]", co_sim);
+               return TCORE_RETURN_EINVAL;
+       }
+
+       req_data = tcore_user_request_ref_data(ur, NULL);
+       if (!req_data) {
+               err("invalid ref data");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       /* supports only faclity type "SC" */
+       if (req_data->type != SIM_FACILITY_SC) {
+               err("Invalid facility type");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       cmd_str = g_strdup_printf("AT+CLCK=\"SC\", %d, \"%s\"",
+                                       mode, req_data->password);
+
+       ret = tcore_prepare_and_send_at_request(co_sim,
+                       cmd_str, "+CLCK:",
+                       TCORE_AT_SINGLELINE,
+                       ur,
+                       on_response_disable_facility, (void *)req_data->type,
+                       NULL, NULL,
+                       0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+       g_free(cmd_str);
+
+       return ret;
+}
+
+static TReturn atd_get_lock_info(CoreObject *co_sim, UserRequest *ur)
+{
+       const struct treq_sim_get_lock_info *req_data;
+       struct atd_sim_property *sp = NULL;
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       dbg("Entry");
+
+       if ((co_sim == NULL) || (ur == NULL)) {
+               err("co: [%p] ur: [%p]", co_sim);
+               return TCORE_RETURN_EINVAL;
+       }
+
+       sp = tcore_sim_ref_userdata(co_sim);
+       if (!sp) {
+               err("sim property is NULL");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       sp->current_sec_op = SEC_LOCK_INFO;
+       req_data = tcore_user_request_ref_data(ur, NULL);
+       if (!req_data) {
+               err("Invalid ref data");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       /* supports only facilty type "SC" */
+       if (req_data->type != SIM_FACILITY_SC) {
+               err("Invalid facility type");
+               return TCORE_RETURN_EINVAL;
+       }
+
+       ret = tcore_prepare_and_send_at_request(co_sim,
+                       "AT+CPIN?", "+CPIN:",
+                       TCORE_AT_SINGLELINE,
+                       ur,
+                       on_response_get_lock_info, NULL,
+                       NULL, NULL,
+                       0, NULL, NULL);
+       dbg("ret: [0x%x]", ret);
+
+       return ret;
+}
+
+static TReturn atd_read_file(CoreObject *co_sim, UserRequest *ur)
+{
+       TReturn api_ret = TCORE_RETURN_SUCCESS;
+       enum tcore_request_command command;
+
+       dbg("Entry");
+
+       if ((co_sim == NULL) || (ur == NULL))
+               return TCORE_RETURN_EINVAL;
+
+       command = tcore_user_request_get_command(ur);
+       if (FALSE == tcore_hal_get_power_state(tcore_object_get_hal(co_sim))) {
+               err("CP NOT READY");
+               return TCORE_RETURN_ENOSYS;
+       }
+
+       switch (command) {
+       default:
+               dbg("error - not handled read treq command[%d]", command);
+               api_ret = TCORE_RETURN_ENOSYS;
+       break;
+       }
+       dbg("Exit");
+       return api_ret;
+}
+
+/**< SIM Operations */
+static struct tcore_sim_operations sim_ops = {
+       .verify_pins = atd_verify_pins,
+       .verify_puks = atd_verify_puks,
+       .change_pins = NULL,
+       .get_facility_status = atd_get_facility_status,
+       .enable_facility = atd_enable_facility,
+       .disable_facility = atd_disable_facility,
+       .get_lock_info = atd_get_lock_info,
+       .read_file = atd_read_file,
+       .update_file = NULL,
+       .transmit_apdu = NULL,
+       .get_atr = NULL,
+       .req_authentication = NULL,
+       .set_powerstate = NULL,
+};
+
+/**< SIM init function */
+gboolean atd_sim_init(TcorePlugin *p, CoreObject *co_sim)
+{
+       struct atd_sim_property *file_meta;
+
+       dbg("Entry");
+
+       file_meta = g_try_new0(struct atd_sim_property, 1);
+       if (file_meta == NULL)
+               return FALSE;
+
+       tcore_sim_link_userdata(co_sim, file_meta);
+
+       /* Set operations */
+       tcore_sim_set_ops(co_sim, &sim_ops, TCORE_OPS_TYPE_CP);
+       dbg("Exit");
+       return TRUE;
+}
+
+/**< SIM exit function */
+void atd_sim_exit(TcorePlugin *p, CoreObject *co_sim)
+{
+       struct atd_sim_property *file_meta;
+
+       dbg("Entry");
+
+       /* Unset 'ops' */
+       tcore_sim_set_ops(co_sim, NULL, TCORE_OPS_TYPE_CP);
+
+       file_meta = tcore_sim_ref_userdata(co_sim);
+       if (file_meta->sim_init_retry_src_id) {
+               dbg("Stop fetching sim status");
+               g_source_remove(file_meta->sim_init_retry_src_id);
+       }
+       g_free(file_meta);
+
+       dbg("Exit");
+}
diff --git a/src/desc-atdongle.c b/src/desc-atdongle.c
new file mode 100644 (file)
index 0000000..8f52ae7
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * tel-plugin-atdongle
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <tcore.h>
+#include <server.h>
+#include <plugin.h>
+#include <core_object.h>
+#include <hal.h>
+#include <at.h>
+
+#include "atd_modem.h"
+#include "atd_sim.h"
+#include "atd_network.h"
+#include "atd_ps.h"
+
+#define STATUS_INFO_RESP               "CPAS"
+
+static void __initialize_device_retry(TcorePlugin *plugin);
+
+static TReturn __send_at_request_immediately(CoreObject *co,
+       const char *at_cmd,
+       const char *at_cmd_prefix,
+       enum tcore_at_command_type at_cmd_type,
+       UserRequest *ur,
+       TcorePendingResponseCallback resp_cb,
+       void *resp_cb_data,
+       TcorePendingSendCallback send_cb,
+       void *send_cb_data,
+       unsigned int timeout,
+       TcorePendingTimeoutCallback timeout_cb,
+       void *timeout_cb_data)
+{
+       TcorePending *pending = NULL;
+       TcoreATRequest *req = NULL;
+       TcoreHal *hal = NULL;
+       TReturn ret = TCORE_RETURN_FAILURE;
+
+       hal = tcore_object_get_hal(co);
+       if (!hal) {
+               dbg("HAL is NULL");
+               return ret;
+       }
+       dbg("hal: [0x%x]", hal);
+
+       /* Create Pending Request */
+       pending = tcore_pending_new(co, 0);
+       if (!pending) {
+               dbg("Pending is NULL");
+               return ret;
+       }
+
+       /* Create AT-Command Request */
+       req = tcore_at_request_new(at_cmd, at_cmd_prefix, at_cmd_type);
+       if (req == NULL) {
+               dbg("Request is NULL");
+               tcore_pending_free(pending);
+               return ret;
+       }
+       dbg("AT Command: [%s], Prefix(if any): [%s], AT-Command length: [%d]",
+                       req->cmd, req->prefix, strlen(req->cmd));
+
+       tcore_pending_set_request_data(pending, 0, req);
+       tcore_pending_set_response_callback(pending, resp_cb, resp_cb_data);
+       tcore_pending_set_send_callback(pending, send_cb, send_cb_data);
+       tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_HIGH);
+       tcore_pending_set_timeout(pending, timeout);
+       tcore_pending_set_timeout_callback(pending, timeout_cb, timeout_cb_data);
+       tcore_pending_link_user_request(pending, ur);
+
+       ret = tcore_hal_send_request(hal, pending);
+       dbg("ret: [0x%x]", ret);
+       return ret;
+}
+
+static void on_response_sync_for_resp(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *at_resp = data;
+       gboolean ret = FALSE;
+
+       if (at_resp && at_resp->success) {
+               dbg("Received - [Success]");
+               /* tty device works successfully. proceed */
+               /* Modem Power on */
+               ret = modem_power_on(user_data);
+               dbg("Modem Power ON: [%s]", (ret == TRUE ? "SUCCESS" : "FAIL"));
+       } else
+               err("Received - [Fail]");
+}
+
+static void __sync_for_resp(TcorePlugin *plugin)
+{
+       CoreObject *co_modem;
+       TReturn ret;
+
+       if (plugin == NULL) {
+               err("Invalid plugin !");
+               return;
+       }
+
+       /* Modem Core object */
+       co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
+
+       /* Some Dongle returns late response
+        * due to its late initialize.
+        *
+        * Send 'meaningless' command
+        * and sync sequence AT response for unexpected response */
+       ret = __send_at_request_immediately(co_modem,
+               "\n", NULL,
+               TCORE_AT_NO_RESULT,
+               NULL,
+               on_response_sync_for_resp, plugin,
+               NULL, NULL,
+               0, NULL, NULL);
+
+       dbg("ret: [0x%x]", ret);
+}
+
+static void on_timeout_initialize_device(TcorePending *p, void *user_data)
+{
+       dbg("Timeout! pending:[%p]", p);
+       dbg(" Try another command to tty device again..");
+
+       /* When AT device doesn't responded with 'AT+CPAS' command,
+        * need to send 'AT' command and check its response..
+        */
+       __initialize_device_retry(user_data);
+}
+
+static void on_response_initialize_device(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *at_resp = data;
+       gboolean ret = FALSE;
+
+       if (at_resp && at_resp->success) {
+               GSList *lines;
+               const char *line;
+               gboolean expected = FALSE;
+
+               dbg("Initialize for AT device - [Success] / Lines: %d",
+                       g_slist_length(at_resp->lines));
+
+               lines = at_resp->lines;
+               while (lines) {
+                       line = (const char *)lines->data;
+
+                       /* Check if response contains 'CPAS' - valid response */
+                       if (g_strrstr(line, STATUS_INFO_RESP)) {
+                               expected = TRUE;
+                               break;
+                       }
+
+                       /* Move to next line */
+                       lines = lines->next;
+               }
+
+               /* Send empty command and wait for valid response */
+               if (expected == FALSE) {
+                       TcorePlugin *plugin = tcore_pending_ref_plugin(p);
+                       dbg("Response contains unexpected lines.");
+                       dbg("Sync AT response");
+                       __sync_for_resp(plugin);
+               } else {
+                       /* tty device works successfully. proceed */
+                       /* Modem Power on */
+                       ret = modem_power_on(user_data);
+                       dbg("Modem Power ON: [%s]", (ret == TRUE ? "SUCCESS" : "FAIL"));
+               }
+       } else {
+               dbg("Initialize for AT device - [Failed]");
+       }
+}
+
+static void on_response_initialize_device_retry(TcorePending *p,
+       int data_len, const void *data, void *user_data)
+{
+       const TcoreATResponse *at_resp = data;
+       gboolean ret = FALSE;
+
+       if (at_resp && at_resp->success) {
+               GSList *lines;
+               const char *line;
+               gboolean unexpected = FALSE;
+
+               dbg("Initialize for AT device - [Success] / Lines: %d",
+                       g_slist_length(at_resp->lines));
+
+               lines = at_resp->lines;
+               while (lines) {
+                       line = (const char *)lines->data;
+
+                       /* Check if response contains 'CPAS' - invalid response */
+                       if (g_strrstr(line, STATUS_INFO_RESP)) {
+                               unexpected = TRUE;
+                               break;
+                       }
+
+                       /* Move to next line */
+                       lines = lines->next;
+               }
+
+               /* Send empty command and wait for valid response */
+               if (unexpected) {
+                       TcorePlugin *plugin = tcore_pending_ref_plugin(p);
+                       dbg("Response contains unexpected lines.");
+                       dbg("Sync AT response");
+                       __sync_for_resp(plugin);
+               } else {
+                       /* tty device works successfully. proceed */
+                       /* Modem Power on */
+                       ret = modem_power_on(user_data);
+                       dbg("Modem Power ON: [%s]", (ret == TRUE ? "SUCCESS" : "FAIL"));
+               }
+       } else {
+               dbg("Initialize for AT device - [Failed]");
+       }
+}
+
+static void __initialize_device(TcorePlugin *plugin)
+{
+       CoreObject *co_modem;
+       TReturn ret;
+
+       if (plugin == NULL) {
+               err("Invalid plugin !");
+               return;
+       }
+
+       /* Modem Core object */
+       co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
+
+       /* Send command and set timeout to 5 sec */
+       ret = tcore_prepare_and_send_at_request(co_modem,
+               "AT+CPAS", NULL,
+               TCORE_AT_MULTILINE,
+               NULL,
+               on_response_initialize_device, plugin,
+               NULL, NULL,
+               5, on_timeout_initialize_device, plugin);
+
+       dbg("ret: [0x%x]", ret);
+}
+
+static void __initialize_device_retry(TcorePlugin *plugin)
+{
+       CoreObject *co_modem;
+       TReturn ret;
+
+       if (plugin == NULL) {
+               err("Invalid plugin !");
+               return;
+       }
+
+       /* Modem Core object */
+       co_modem = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM);
+
+       /* Send 'AT' command and set timeout to 5 sec */
+       ret = tcore_prepare_and_send_at_request(co_modem,
+               "AT", NULL,
+               TCORE_AT_MULTILINE,
+               NULL,
+               on_response_initialize_device_retry, plugin,
+               NULL, NULL,
+               5, on_timeout_initialize_device, plugin);
+
+       dbg("ret: [0x%x]", ret);
+}
+
+/**< Initializer Table */
+struct object_initializer init_table = {
+       .modem_init = atd_modem_init,
+       .sim_init = atd_sim_init,
+       .network_init = atd_network_init,
+       .ps_init = atd_ps_init,
+       .sat_init = NULL,
+       .sap_init = NULL,
+       .call_init = NULL,
+       .ss_init = NULL,
+       .sms_init = NULL,
+       .phonebook_init = NULL,
+       .gps_init = NULL,
+};
+
+/**< Deinitializer Table */
+struct object_deinitializer deinit_table = {
+       .modem_deinit = atd_modem_exit,
+       .sim_deinit = atd_sim_exit,
+       .ps_deinit = atd_ps_exit,
+       .network_deinit = atd_network_exit,
+       .sat_deinit = NULL,
+       .sap_deinit = NULL,
+       .call_deinit = NULL,
+       .ss_deinit = NULL,
+       .sms_deinit = NULL,
+       .phonebook_deinit = NULL,
+       .gps_deinit = NULL,
+};
+
+static gboolean on_load()
+{
+       dbg("Load!!!");
+
+       return TRUE;
+}
+
+static gboolean on_init(TcorePlugin *p)
+{
+       dbg("Init!!!");
+
+       if (p == NULL) {
+               err("invalid plugin!!");
+               return FALSE;
+       }
+
+       /* Initialize Modules (Core Objects) */
+       if (tcore_object_init_objects(p, &init_table)
+                       != TCORE_RETURN_SUCCESS) {
+               err("Failed to initialize Core Objects");
+               return FALSE;
+       }
+
+       /* Initialize tty device */
+       __initialize_device(p);
+
+       dbg("Init - Complete!");
+
+       return TRUE;
+}
+
+static void on_unload(TcorePlugin *p)
+{
+       dbg("Unload!!!");
+
+       /* Deinitialize Modules (Core Objects) */
+       tcore_object_deinit_objects(p, &deinit_table);
+}
+
+/* AT Dongle - Modem Plug-in Descriptor */
+struct tcore_plugin_define_desc plugin_define_desc = {
+       .name = "ATDONGLE",
+       .priority = TCORE_PLUGIN_PRIORITY_MID,
+       .version = 1,
+       .load = on_load,
+       .init = on_init,
+       .unload = on_unload
+};
diff --git a/tel-plugin-atdongle.manifest b/tel-plugin-atdongle.manifest
new file mode 100644 (file)
index 0000000..97e8c31
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>