+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <errno.h>
+#include <vconf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <vconf-keys.h>
+#include <ITapiSim.h>
+#include <TapiUtility.h>
+
+#include "plugin.h"
+
+#ifdef USE_NETCONFIG_LOG
+#include "log.h"
+#else
+#include <dlog.h>
+
+#define NETCONFIG_TAG "NETCONFIG"
+#define __LOG(level, format, arg...) \
+ do { \
+ SLOG(level, NETCONFIG_TAG, format, ## arg); \
+ } while (0)
+
+#define DBG(format, arg...) __LOG(LOG_DEBUG, format, ## arg)
+#define ERR(format, arg...) __LOG(LOG_ERROR, format, ## arg)
+#endif
+
+#define TAPI_HANDLE_MAX 2
+
+/* #define SIM_SLOT_DUAL 2 */
+#define SIM_SLOT_SINGLE 1
+
+#define VCONF_TELEPHONY_DEFAULT_DATA_SERVICE "db/telephony/dualsim/default_data_service"
+/*
+#define DEFAULT_DATA_SERVICE_SIM1 0
+#define DEFAULT_DATA_SERVICE_SIM2 1
+*/
+#define SIM_RAND_DATA_LEN 16
+#define SIM_AUTH_MAX_RESP_DATA_LEN 128
+#define SIM_AUTH_SRES_LEN 4
+#define SIM_AUTH_KC_LEN 8
+
+#define AKA_RAND_DATA_LEN 16
+#define AKA_AUTN_DATA_LEN 16
+#define AKA_AUTH_RES_MAX_LEN 16
+#define AKA_AUTH_RES_MIN_LEN 4
+#define AKA_AUTH_CK_LEN 16
+#define AKA_AUTH_IK_LEN 16
+
+static TapiHandle *tapi_handle_dual[TAPI_HANDLE_MAX+1];
+static TapiHandle *tapi_handle = NULL;
+struct wifi_authentication_data **wifi_authdata_p = NULL;
+
+#define wifi_authdata (*wifi_authdata_p)
+
+static int _check_current_sim()
+{
+#if defined TIZEN_WEARABLE
+ return -1;
+#else
+ int current_sim = 0;
+ int sim_slot_count = 0;
+
+ if ((vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT_COUNT, &sim_slot_count) != 0)
+ || sim_slot_count == SIM_SLOT_SINGLE) {
+ ERR("failed to get sim slot count (%d)", sim_slot_count);
+ return -1;
+ }
+
+ if (vconf_get_int(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE, ¤t_sim) != 0) {
+ ERR("failed to get default data service = %d\n", current_sim);
+ return 0;
+ }
+
+ DBG("default data service [SIM%d]", current_sim);
+ return current_sim;
+#endif
+}
+
+static TapiHandle * netconfig_tel_init(void)
+{
+ char **cp_list = NULL;
+ int current_sim = _check_current_sim();
+
+ if (current_sim < 0) {
+ if (tapi_handle == NULL) {
+ tapi_handle = tel_init(NULL);
+ if (tapi_handle == NULL)
+ ERR("tel_init() Failed - modem %d", current_sim);
+ }
+ return tapi_handle;
+ } else {
+ if (tapi_handle_dual[current_sim] == NULL) {
+ cp_list = tel_get_cp_name_list();
+ if (!cp_list) {
+ ERR("tel_get_cp_name_list() Failed");
+ return NULL;
+ }
+
+ tapi_handle_dual[current_sim] = tel_init(cp_list[current_sim]);
+ if (tapi_handle_dual[current_sim] == NULL)
+ ERR("tel_init() Failed - modem %d", current_sim);
+
+ g_strfreev(cp_list);
+ }
+ return tapi_handle_dual[current_sim];
+ }
+}
+
+static void netconfig_tel_deinit(void)
+{
+ int current_sim = _check_current_sim();
+
+ if (current_sim < 0) {
+ if (tapi_handle)
+ tel_deinit(tapi_handle);
+
+ tapi_handle = NULL;
+ } else {
+ unsigned int i = 0;
+ while (tapi_handle_dual[i]) {
+ tel_deinit(tapi_handle_dual[i]);
+ tapi_handle_dual[i] = NULL;
+ i++;
+ }
+ }
+}
+
+void telephony_get_network_type(int *svctype, int *pstype)
+{
+ TapiHandle *tapi_handle = NULL;
+ int telephony_svctype = 0, telephony_pstype = 0;
+
+ tapi_handle = (TapiHandle *)netconfig_tel_init();
+
+ if (NULL != tapi_handle) {
+ tel_get_property_int(tapi_handle,
+ TAPI_PROP_NETWORK_SERVICE_TYPE,
+ &telephony_svctype);
+ tel_get_property_int(tapi_handle, TAPI_PROP_NETWORK_PS_TYPE,
+ &telephony_pstype);
+ netconfig_tel_deinit();
+ }
+
+ *svctype = telephony_svctype;
+ *pstype = telephony_pstype;
+}
+
+gboolean telephony_wifi_get_sim_imsi(void *wifi, GDBusMethodInvocation *context)
+{
+ int ret;
+ TapiHandle *handle;
+ TelSimImsiInfo_t imsi_info;
+ char *imsi;
+
+ handle = (TapiHandle *)netconfig_tel_init();
+ if (handle == NULL) {
+ ERR("tapi_init failed");
+ netconfig_error_fail_get_imsi(context);
+ return FALSE;
+ }
+
+ ERR("before tel_get_sim_imsi");
+ ret = tel_get_sim_imsi(handle, &imsi_info);
+ ERR("after tel_get_sim_imsi");
+ if (ret != TAPI_API_SUCCESS) {
+ ERR("Failed tel_get_sim_imsi() : [%d]", ret);
+ netconfig_error_fail_get_imsi(context);
+ return FALSE;
+ }
+
+ imsi = g_strdup_printf("%s%s%s", imsi_info.szMcc,
+ imsi_info.szMnc, imsi_info.szMsin);
+
+ netconfig_complete_get_sim_imsi(wifi, context, imsi);
+ g_free(imsi);
+
+ return TRUE;
+}
+
+static void *__telephony_wifi_free_wifi_authdata(
+ struct wifi_authentication_data *data)
+{
+ if (data != NULL) {
+ if (data->resp_data)
+ g_free(data->resp_data);
+ if (data->authentication_key)
+ g_free(data->authentication_key);
+ if (data->cipher_data)
+ g_free(data->cipher_data);
+ if (data->integrity_data)
+ g_free(data->integrity_data);
+
+ g_free(data);
+ data = NULL;
+ }
+
+ return NULL;
+}
+
+static void __telephony_response_aka_authentication(TapiHandle *handle,
+ int result, void *data, void *user_data)
+{
+ if (wifi_authdata != NULL)
+ wifi_authdata = __telephony_wifi_free_wifi_authdata(wifi_authdata);
+
+ wifi_authdata = g_try_new0(struct wifi_authentication_data, 1);
+
+ if (wifi_authdata == NULL) {
+ ERR("Out of Memory!");
+ return;
+ }
+
+ TelSimAuthenticationResponse_t *auth_resp =
+ (TelSimAuthenticationResponse_t *) data;
+ if (auth_resp == NULL) {
+ ERR("the auth response is NULL");
+
+ wifi_authdata->auth_result = -1;
+ return;
+ } else
+ wifi_authdata->auth_result = auth_resp->auth_result;
+
+ if (auth_resp->auth_result == TAPI_SIM_AUTH_NO_ERROR) {
+ wifi_authdata->resp_length = auth_resp->resp_length;
+ wifi_authdata->cipher_length = auth_resp->cipher_length;
+ wifi_authdata->integrity_length = auth_resp->integrity_length;
+
+ if (wifi_authdata->resp_data != NULL)
+ g_free(wifi_authdata->resp_data);
+
+ wifi_authdata->resp_data = g_strdup(auth_resp->resp_data);
+
+ if (wifi_authdata->cipher_data != NULL)
+ g_free(wifi_authdata->cipher_data);
+
+ wifi_authdata->cipher_data = g_strdup(auth_resp->cipher_data);
+
+ if (wifi_authdata->integrity_data != NULL)
+ g_free(wifi_authdata->integrity_data);
+
+ wifi_authdata->integrity_data = g_strdup(auth_resp->integrity_data);
+ } else {
+ ERR("the result error for aka auth : [%d]", auth_resp->auth_result);
+
+ if (auth_resp->auth_result == TAPI_SIM_AUTH_SQN_FAILURE ||
+ auth_resp->auth_result == TAPI_SIM_AUTH_SYNCH_FAILURE) {
+ wifi_authdata->resp_length = auth_resp->resp_length;
+
+ if (wifi_authdata->resp_data != NULL)
+ g_free(wifi_authdata->resp_data);
+
+ wifi_authdata->resp_data = g_strdup(auth_resp->resp_data);
+ }
+ }
+}
+
+netconfig_error_e telephony_wifi_req_aka_auth(GArray *rand_data, GArray *autn_data,
+ GDBusMethodInvocation *context, struct wifi_authentication_data **data)
+{
+ int i;
+ int ret;
+ TapiHandle *handle;
+ TelSimAuthenticationData_t auth_data;
+
+ if (!wifi_authdata_p)
+ wifi_authdata_p = data;
+
+ if (rand_data == NULL || autn_data == NULL)
+ return NETCONFIG_ERROR_FAILED_REQ_SIM_AUTH;
+
+ if (rand_data->len != AKA_RAND_DATA_LEN) {
+ ERR("wrong rand data len : [%d]", rand_data->len);
+
+ return NETCONFIG_ERROR_FAILED_REQ_SIM_AUTH_WRONG_PARAM;
+ }
+
+ if (autn_data->len != AKA_AUTN_DATA_LEN) {
+ ERR("wrong autn data len : [%d]", autn_data->len);
+
+ return NETCONFIG_ERROR_FAILED_REQ_SIM_AUTH_WRONG_PARAM;
+ }
+
+ if ((ret = g_array_get_element_size(rand_data)) != 1) {
+ ERR("wrong rand data size : [%d]", ret);
+
+ return NETCONFIG_ERROR_FAILED_REQ_SIM_AUTH_WRONG_PARAM;
+ }
+
+ if ((ret = g_array_get_element_size(autn_data)) != 1) {
+ ERR("wrong autn data size : [%d]", ret);
+
+ return NETCONFIG_ERROR_FAILED_REQ_SIM_AUTH_WRONG_PARAM;
+ }
+
+ memset(&auth_data, 0, sizeof(auth_data));
+
+ auth_data.auth_type = TAPI_SIM_AUTH_TYPE_3G;
+ auth_data.rand_length = AKA_RAND_DATA_LEN;
+ auth_data.autn_length = AKA_AUTN_DATA_LEN;
+
+ for (i = 0; i < rand_data->len; i++)
+ auth_data.rand_data[i] = g_array_index(rand_data, guint8, i);
+
+ for (i = 0; i < autn_data->len; i++)
+ auth_data.autn_data[i] = g_array_index(autn_data, guint8, i);
+
+ handle = (TapiHandle *)netconfig_tel_init();
+ if (handle == NULL)
+ return NETCONFIG_ERROR_FAILED_REQ_SIM_AUTH;
+
+ ret = tel_req_sim_authentication(handle, &auth_data,
+ __telephony_response_aka_authentication, NULL);
+
+ if (ret != TAPI_API_SUCCESS) {
+ ERR("Failed tel_req_sim_authentication() : [%d]", ret);
+
+ return NETCONFIG_ERROR_FAILED_REQ_SIM_AUTH;
+ }
+ return NETCONFIG_NO_ERROR;
+}
+
+static void telephony_response_sim_authentication(TapiHandle *handle,
+ int result, void *data, void *user_data)
+{
+ if (wifi_authdata != NULL)
+ wifi_authdata = __telephony_wifi_free_wifi_authdata(wifi_authdata);
+
+ wifi_authdata = g_try_new0(struct wifi_authentication_data, 1);
+
+ if (wifi_authdata == NULL) {
+ ERR("Out of Memory!");
+ return;
+ }
+
+ TelSimAuthenticationResponse_t *auth_resp =
+ (TelSimAuthenticationResponse_t *) data;
+ if (auth_resp == NULL) {
+ ERR("the auth response is NULL");
+
+ wifi_authdata->auth_result = -1;
+ return;
+ } else
+ wifi_authdata->auth_result = auth_resp->auth_result;
+
+ if (auth_resp->auth_result == TAPI_SIM_AUTH_NO_ERROR) {
+ wifi_authdata->resp_length = auth_resp->resp_length;
+ wifi_authdata->authentication_key_length =
+ auth_resp->authentication_key_length;
+
+ if (wifi_authdata->resp_data != NULL)
+ g_free(wifi_authdata->resp_data);
+
+ wifi_authdata->resp_data = g_strdup(auth_resp->resp_data);
+
+ if (wifi_authdata->authentication_key != NULL)
+ g_free(wifi_authdata->authentication_key);
+
+ wifi_authdata->authentication_key = g_strdup(auth_resp->authentication_key);
+ } else {
+ ERR("the result error for sim auth : [%d]", auth_resp->auth_result);
+
+ wifi_authdata->resp_length = 0;
+ wifi_authdata->authentication_key_length = 0;
+ }
+}
+
+gboolean telephony_wifi_req_sim_auth(GArray *rand_data,
+ GDBusMethodInvocation *context, struct wifi_authentication_data **data)
+{
+ int i;
+ int ret;
+ TapiHandle *handle;
+ TelSimAuthenticationData_t auth_data;
+
+ if (!wifi_authdata_p)
+ wifi_authdata_p = data;
+
+ if (rand_data == NULL)
+ return FALSE;
+
+ if (rand_data->len != SIM_RAND_DATA_LEN) {
+ ERR("wrong rand data len : [%d]", rand_data->len);
+
+ netconfig_error_fail_req_sim_auth_wrong_param(context);
+ return FALSE;
+ }
+
+ if ((ret = g_array_get_element_size(rand_data)) != 1) {
+ ERR("wrong rand data size : [%d]", ret);
+
+ netconfig_error_fail_req_sim_auth_wrong_param(context);
+ return FALSE;
+ }
+
+ memset(&auth_data, 0, sizeof(auth_data));
+
+ auth_data.auth_type = TAPI_SIM_AUTH_TYPE_GSM;
+ auth_data.rand_length = SIM_RAND_DATA_LEN;
+
+ for (i = 0; i < rand_data->len; i++)
+ auth_data.rand_data[i] = g_array_index(rand_data, guint8, i);
+
+ handle = (TapiHandle *)netconfig_tel_init();
+ if (handle == NULL) {
+ netconfig_error_fail_req_sim_auth(context);
+ return FALSE;
+ }
+
+ ret = tel_req_sim_authentication(handle,
+ &auth_data, telephony_response_sim_authentication, NULL);
+ if (ret != TAPI_API_SUCCESS) {
+ ERR("Failed tel_req_sim_authentication() : [%d]", ret);
+
+ netconfig_error_fail_req_sim_auth(context);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void telephony_noti_sim_status_cb(TapiHandle *handle, const char *noti_id,
+ void *data, void *user_data)
+{
+ TelSimCardStatus_t *status = data;
+
+ if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
+ DBG("Turn Wi-Fi on automatically");
+
+ netconfig_wifi_power_on();
+ netconfig_tel_deinit();
+ }
+}
+
+gboolean telephony_tapi_check_sim_state(void)
+{
+ int ret, card_changed;
+ TelSimCardStatus_t status = TAPI_SIM_STATUS_UNKNOWN;
+ TapiHandle *tapi_handle = NULL;
+
+ tapi_handle = (TapiHandle *)netconfig_tel_init();
+ if (tapi_handle == NULL) {
+ ERR("Failed to tapi init");
+ return FALSE;
+ }
+
+ ret = tel_get_sim_init_info(tapi_handle, &status, &card_changed);
+ if (ret != TAPI_API_SUCCESS) {
+ ERR("tel_get_sim_init_info() Failed : [%d]", ret);
+ netconfig_tel_deinit();
+ return FALSE;
+ }
+
+ switch (status) {
+ case TAPI_SIM_STATUS_UNKNOWN:
+ case TAPI_SIM_STATUS_CARD_ERROR:
+ case TAPI_SIM_STATUS_CARD_NOT_PRESENT:
+ case TAPI_SIM_STATUS_CARD_BLOCKED:
+ case TAPI_SIM_STATUS_SIM_INIT_COMPLETED:
+ break;
+ case TAPI_SIM_STATUS_SIM_PIN_REQUIRED:
+ case TAPI_SIM_STATUS_SIM_INITIALIZING:
+ case TAPI_SIM_STATUS_SIM_PUK_REQUIRED:
+ case TAPI_SIM_STATUS_SIM_LOCK_REQUIRED:
+ case TAPI_SIM_STATUS_SIM_NCK_REQUIRED:
+ case TAPI_SIM_STATUS_SIM_NSCK_REQUIRED:
+ case TAPI_SIM_STATUS_SIM_SPCK_REQUIRED:
+ case TAPI_SIM_STATUS_SIM_CCK_REQUIRED:
+ tel_register_noti_event(tapi_handle, TAPI_NOTI_SIM_STATUS,
+ telephony_noti_sim_status_cb, NULL);
+ return FALSE;
+ default:
+ ERR("not defined status(%d)", status);
+ break;
+ }
+
+ netconfig_tel_deinit();
+
+ return TRUE;
+}
+
+static void __telephony_wifi_clean_authentication(void)
+{
+ netconfig_tel_deinit();
+
+ wifi_authdata = __telephony_wifi_free_wifi_authdata(wifi_authdata);
+}
+
+gboolean telephony_wifi_get_aka_authdata(void *wifi,
+ GDBusMethodInvocation *context, struct wifi_authentication_data **data)
+{
+ GArray *array = NULL;
+ guchar res_len;
+
+ if (!wifi_authdata_p)
+ wifi_authdata_p = data;
+
+ if (wifi_authdata == NULL) {
+ DBG("the status error : no response yet");
+ netconfig_error_fail_get_sim_auth_delay(context);
+ return FALSE;
+ }
+
+ switch (wifi_authdata->auth_result) {
+ case TAPI_SIM_AUTH_NO_ERROR:
+ break;
+
+ case TAPI_SIM_AUTH_SQN_FAILURE:
+ case TAPI_SIM_AUTH_SYNCH_FAILURE:
+ array = g_array_sized_new(FALSE, FALSE, sizeof(guchar),
+ wifi_authdata->resp_length+1);
+ res_len = (guchar)((wifi_authdata->resp_length-1) & 0xff);
+
+ g_array_append_vals(array, &res_len, 1);
+ g_array_append_vals(array, wifi_authdata->resp_data,
+ wifi_authdata->resp_length);
+
+ netconfig_complete_get_aka_auth(wifi, context, array);
+ g_array_free(array, TRUE);
+
+ __telephony_wifi_clean_authentication();
+
+ return TRUE;
+
+ default:
+ netconfig_error_fail_get_sim_auth_wrong_data(context);
+ __telephony_wifi_clean_authentication();
+ return FALSE;
+ }
+
+ if ((wifi_authdata->resp_length >= AKA_AUTH_RES_MIN_LEN ||
+ wifi_authdata->resp_length <= AKA_AUTH_RES_MAX_LEN) &&
+ wifi_authdata->cipher_length == AKA_AUTH_CK_LEN &&
+ wifi_authdata->integrity_length == AKA_AUTH_IK_LEN) {
+ array = g_array_sized_new(FALSE, FALSE, sizeof(guchar),
+ wifi_authdata->resp_length+AKA_AUTH_CK_LEN+AKA_AUTH_IK_LEN+1);
+
+ res_len = (guchar)((wifi_authdata->resp_length-1) & 0xff);
+ g_array_append_vals(array, &res_len, 1);
+ g_array_append_vals(array, wifi_authdata->resp_data,
+ wifi_authdata->resp_length);
+ g_array_append_vals(array, wifi_authdata->cipher_data,
+ AKA_AUTH_CK_LEN);
+ g_array_append_vals(array, wifi_authdata->integrity_data,
+ AKA_AUTH_IK_LEN);
+ } else {
+ ERR("auth data length is wrong, res = [%d], Kc = [%d], Ki = [%d]",
+ wifi_authdata->resp_length, wifi_authdata->cipher_length,
+ wifi_authdata->integrity_length);
+
+ netconfig_error_fail_get_sim_auth_wrong_data(context);
+ __telephony_wifi_clean_authentication();
+ return FALSE;
+ }
+
+ netconfig_complete_get_aka_auth(wifi, context, array);
+ g_array_free(array, TRUE);
+ __telephony_wifi_clean_authentication();
+
+ return TRUE;
+}
+
+gboolean telephony_wifi_get_sim_authdata(void *wifi,
+ GDBusMethodInvocation *context, struct wifi_authentication_data **data)
+{
+ GArray *array = NULL;
+
+ if (!wifi_authdata_p)
+ wifi_authdata_p = data;
+
+ if (wifi_authdata == NULL) {
+ DBG("the status error : no response yet");
+ netconfig_error_fail_get_sim_auth_delay(context);
+ return FALSE;
+ }
+
+ if (wifi_authdata->auth_result == TAPI_SIM_AUTH_NO_ERROR) {
+ if (wifi_authdata->resp_length == SIM_AUTH_SRES_LEN &&
+ wifi_authdata->authentication_key_length == SIM_AUTH_KC_LEN) {
+ array = g_array_sized_new(FALSE, FALSE, sizeof(guchar),
+ SIM_AUTH_SRES_LEN+SIM_AUTH_KC_LEN);
+ g_array_append_vals(array, wifi_authdata->resp_data,
+ SIM_AUTH_SRES_LEN);
+ g_array_append_vals(array, wifi_authdata->authentication_key,
+ SIM_AUTH_KC_LEN);
+ } else {
+ ERR("auth data length is wrong, SRES = [%d], Kc = [%d]",
+ wifi_authdata->resp_length,
+ wifi_authdata->authentication_key_length);
+ netconfig_error_fail_get_sim_auth_wrong_data(context);
+ __telephony_wifi_clean_authentication();
+ return FALSE;
+ }
+ } else {
+ ERR("failed auth result = [%d]", wifi_authdata->auth_result);
+ netconfig_error_fail_get_sim_auth_wrong_data(context);
+ __telephony_wifi_clean_authentication();
+ return FALSE;
+ }
+
+ netconfig_complete_get_sim_auth(wifi, context, array);
+ g_array_free(array, TRUE);
+ __telephony_wifi_clean_authentication();
+ return TRUE;
+}
+
+
+extern struct netconfig_telephony_plugin_t netconfig_telephony_plugin
+ __attribute__ ((visibility("default")));
+struct netconfig_telephony_plugin_t netconfig_telephony_plugin = {
+ telephony_get_network_type,
+ telephony_wifi_get_sim_imsi,
+ telephony_wifi_req_aka_auth,
+ telephony_wifi_req_sim_auth,
+ telephony_tapi_check_sim_state,
+ telephony_wifi_get_aka_authdata,
+ telephony_wifi_get_sim_authdata
+};
+