| /*-----------------------------------------------------------------------------------------------*/ | 
 | /** | 
 |   @file lynq_data_call.c  | 
 |   @brief data call service API  | 
 | */ | 
 | /*-----------------------------------------------------------------------------------------------*/ | 
 |  | 
 | /*------------------------------------------------------------------------------------------------- | 
 |   Copyright (c) 2024 mobiletek Wireless Solution, Co., Ltd. All Rights Reserved. | 
 |   mobiletek Wireless Solution Proprietary and Confidential. | 
 | -------------------------------------------------------------------------------------------------*/ | 
 |  | 
 | /*------------------------------------------------------------------------------------------------- | 
 |   EDIT HISTORY | 
 |   This section contains comments describing changes made to the file. | 
 |   Notice that changes are listed in reverse chronological order. | 
 |   $Header: $ | 
 |   when       who          what, where, why | 
 |   --------   ---------    ----------------------------------------------------------------- | 
 |   20241202    yq.wang      Created. | 
 | -------------------------------------------------------------------------------------------------*/ | 
 |  | 
 | #include <pthread.h> | 
 | #include <cutils/properties.h> | 
 | #include <string.h> | 
 | #include <unistd.h> | 
 | #include <sys/types.h> | 
 | #include <sys/stat.h> | 
 | #include <fcntl.h> | 
 | //#include <sys/scoket.h> | 
 | #include <netinet/in.h> | 
 | #include <arpa/inet.h> | 
 |  | 
 | #include "lynq_qser_data.h" | 
 | #include "mbtk_type.h" | 
 | #include "mbtk_ril_api.h" | 
 |  | 
 | /*define*/ | 
 | #define QSER_DATA_CALL_FUNC __func__ | 
 |  | 
 | #define QSER_LOGE LOGE | 
 | #define QSER_LOGD LOGD | 
 |  | 
 | #define QSER_DEFAULT_APN_TYPE "iot_default" | 
 |  | 
 | /*define*/ | 
 |  | 
 | /*enum*/ | 
 | typedef enum { | 
 | 	QSER_RESULT_SUCCESS = 0, | 
 |     QSER_RESULT_FAIL, | 
 |     QSER_RESULT_SERVER_NO_INIT, | 
 |     QSER_RESULT_INVALID_PARAMS, | 
 | }qser_result_e; | 
 |  | 
 | /*enum*/ | 
 |  | 
 | /*struct*/ | 
 | typedef struct { | 
 |     mbtk_ril_handle* handle; | 
 |     qser_data_call_evt_cb_t net_status_cb; | 
 | }qser_data_call_handle_s; | 
 |  | 
 | /*struct*/ | 
 |  | 
 | /*----------------------------------------------DATA CALL FUNCTION-------------------------------------*/ | 
 | static qser_data_call_handle_s* qser_data_call_handle_get(void) | 
 | { | 
 |     static qser_data_call_handle_s data_call_handle = {0}; | 
 |      | 
 |     return &data_call_handle; | 
 | } | 
 |  | 
 | static int qser_apn_convert_to_qser_s(qser_apn_info_s *qser_apn, mbtk_apn_info_t *mbtk_apn) | 
 | { | 
 |     if(qser_apn == NULL || mbtk_apn == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] apn param is NULL.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     int length = 0; | 
 |     memset(qser_apn, 0x0, sizeof(qser_apn_info_s)); | 
 |     qser_apn->profile_idx = (unsigned char)(mbtk_apn->cid - 1); | 
 |     //get ip type | 
 |     if(mbtk_apn->ip_type == MBTK_IP_TYPE_IPV4V6) // IPV4V6 | 
 |     { | 
 |         qser_apn->pdp_type = QSER_APN_PDP_TYPE_IPV4V6; | 
 |     } | 
 |     else if(mbtk_apn->ip_type == MBTK_IP_TYPE_IP) // IPV4 | 
 |     { | 
 |         qser_apn->pdp_type = QSER_APN_PDP_TYPE_IPV4; | 
 |     } | 
 |     else if(mbtk_apn->ip_type == MBTK_IP_TYPE_IPV6) // IPV6 | 
 |     { | 
 |         qser_apn->pdp_type = QSER_APN_PDP_TYPE_IPV6; | 
 |     } | 
 |     else | 
 |     { | 
 |         qser_apn->pdp_type = QSER_APN_PDP_TYPE_PPP; | 
 |     } | 
 |  | 
 |     //get apn proto | 
 |     qser_apn->auth_proto = (qser_apn_auth_proto_e)mbtk_apn->auth; | 
 |      | 
 |     //get apn name | 
 |     length = strlen((char *)mbtk_apn->apn); | 
 |     if( length <= 0 || length > QSER_APN_NAME_SIZE) | 
 |     { | 
 |         QSER_LOGE("[%s] apn_nmea length fault.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         memcpy(qser_apn->apn_name, mbtk_apn->apn, length); | 
 |     } | 
 |  | 
 |     //get apn user | 
 |     length = strlen((char *)mbtk_apn->user); | 
 |     if(length < 0 || length > QSER_APN_USERNAME_SIZE) | 
 |     { | 
 |         QSER_LOGE("[%s] user length fault.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         memcpy(qser_apn->username, mbtk_apn->user, length); | 
 |     } | 
 |  | 
 |     //get apn password | 
 |     length = strlen((char *)mbtk_apn->pass); | 
 |     if(length < 0 || length > QSER_APN_PASSWORD_SIZE) | 
 |     { | 
 |         QSER_LOGE("[%s] pass length fault.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         memcpy(qser_apn->password, mbtk_apn->pass, length); | 
 |     } | 
 |  | 
 |     //get apn type | 
 |     length = strlen((char *)mbtk_apn->type); | 
 |     if(length < 0 || length > QSER_APN_TYPE_SIZE) | 
 |     { | 
 |         QSER_LOGE("[%s] type length fault.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         memcpy(qser_apn->apn_type, mbtk_apn->type, length); | 
 |     } | 
 |  | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | static int qser_apn_convert_to_mbtk_s(mbtk_ril_cid_enum cid, mbtk_apn_info_t *mbtk_apn, qser_apn_info_s *qser_apn) | 
 | { | 
 |     if(mbtk_apn == NULL || qser_apn == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] apn param is NULL.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |      | 
 |     if(strlen(qser_apn->apn_name) > QSER_APN_NAME_SIZE || strlen(qser_apn->username) > QSER_APN_USERNAME_SIZE | 
 |                || strlen(qser_apn->password) > QSER_APN_PASSWORD_SIZE  || strlen(qser_apn->apn_type) > QSER_APN_TYPE_SIZE) | 
 |     { | 
 |         QSER_LOGE("[%s] apn length out of range.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_INVALID_PARAMS; | 
 |     } | 
 |  | 
 |     memset(mbtk_apn, 0x0, sizeof(mbtk_apn_info_t)); | 
 |     mbtk_apn->cid = cid; | 
 |      | 
 |     if(qser_apn->pdp_type == QSER_APN_PDP_TYPE_IPV4) | 
 |     { | 
 |         mbtk_apn->ip_type = MBTK_IP_TYPE_IP; | 
 |     } | 
 |     else if(qser_apn->pdp_type == QSER_APN_PDP_TYPE_IPV6) | 
 |     { | 
 |         mbtk_apn->ip_type = MBTK_IP_TYPE_IPV6; | 
 |     } | 
 |     else if(qser_apn->pdp_type == QSER_APN_PDP_TYPE_IPV4V6) | 
 |     { | 
 |         mbtk_apn->ip_type = MBTK_IP_TYPE_IPV4V6; | 
 |     } | 
 |     else if(qser_apn->pdp_type == QSER_APN_PDP_TYPE_PPP) | 
 |     { | 
 |         mbtk_apn->ip_type = MBTK_IP_TYPE_PPP; | 
 |     } | 
 |     else | 
 |     { | 
 |         QSER_LOGE("[%s] pdp_type error.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     //no support PAP_CHAP | 
 |     if(qser_apn->auth_proto >= QSER_APN_AUTH_PROTO_DEFAULT && qser_apn->auth_proto < QSER_APN_AUTH_PROTO_PAP_CHAP) | 
 |     { | 
 |         mbtk_apn->auth = (mbtk_apn_auth_type_enum)qser_apn->auth_proto; | 
 |     } | 
 |     else | 
 |     { | 
 |         QSER_LOGE("[%s] auth_proto error.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |      | 
 |     mbtk_apn->auto_save = true; | 
 |     mbtk_apn->auto_boot_call = false; | 
 |  | 
 |     if(strlen(qser_apn->apn_type)) | 
 |     { | 
 |         if(memcmp(qser_apn->apn_type, QSER_DEFAULT_APN_TYPE, strlen(QSER_DEFAULT_APN_TYPE)) == 0) | 
 |         { | 
 |             mbtk_apn->def_route = true; | 
 |             mbtk_apn->as_dns = true; | 
 |         } | 
 |         memcpy(mbtk_apn->type, qser_apn->apn_type, strlen(qser_apn->apn_type)); | 
 |     } | 
 |     else | 
 |     { | 
 |         mbtk_apn->def_route = false; | 
 |         mbtk_apn->as_dns = false; | 
 |     } | 
 |      | 
 |     if(strlen(qser_apn->apn_name)) | 
 |     { | 
 |         memcpy(mbtk_apn->apn, qser_apn->apn_name, strlen(qser_apn->apn_name)); | 
 |     } | 
 |     else | 
 |     { | 
 |         QSER_LOGE("[%s] apn is empty.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |      | 
 |     if(strlen(qser_apn->username)) | 
 |     { | 
 |         memcpy(mbtk_apn->user, qser_apn->username, strlen(qser_apn->username)); | 
 |     } | 
 |     if(strlen(qser_apn->password)) | 
 |     { | 
 |         memcpy(mbtk_apn->pass, qser_apn->password, strlen(qser_apn->password)); | 
 |     } | 
 |  | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | static void qser_netcard_state_init(qser_data_call_state_s *state) | 
 | { | 
 |     if(state != NULL) | 
 |     { | 
 |         state->profile_idx = 0; | 
 |         memset(state->name, 0x0, 16); | 
 |         state->ip_family = QSER_DATA_CALL_TYPE_IPV4V6; | 
 |         state->state = QSER_DATA_CALL_DISCONNECTED; | 
 |         state->err = QSER_DATA_CALL_ERROR_NONE; | 
 |         inet_aton("0.0.0.0", &(state->v4.ip)); | 
 |         inet_aton("0.0.0.0", &(state->v4.gateway)); | 
 |         inet_aton("0.0.0.0", &(state->v4.pri_dns)); | 
 |         inet_aton("0.0.0.0", &(state->v4.sec_dns)); | 
 |         inet_pton(AF_INET6, "::", &(state->v6.ip)); | 
 |         inet_pton(AF_INET6, "::", &(state->v6.gateway)); | 
 |         inet_pton(AF_INET6, "::", &(state->v6.pri_dns)); | 
 |         inet_pton(AF_INET6, "::", &(state->v6.sec_dns)); | 
 |     } | 
 | } | 
 |  | 
 | static void qser_pdp_state_change_cb(const void* data, int data_len) | 
 | { | 
 |     if(data == NULL || data_len != sizeof(mbtk_ril_pdp_state_info_t)) | 
 |     { | 
 |         QSER_LOGE("[%s] cb data fault.", QSER_DATA_CALL_FUNC); | 
 |         return; | 
 |     } | 
 |      | 
 |     mbtk_ril_pdp_state_info_t pdp_data; | 
 |     qser_data_call_state_s state = {0}; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle) | 
 |     { | 
 |         QSER_LOGE("[%s] qser_data_call_handle_get() fail.", QSER_DATA_CALL_FUNC); | 
 |         return; | 
 |     } | 
 |  | 
 |      | 
 |     memset(&pdp_data, 0x0, sizeof(mbtk_ril_pdp_state_info_t)); | 
 |     memcpy(&pdp_data, data, sizeof(mbtk_ril_pdp_state_info_t)); | 
 |     QSER_LOGD("[%s] cid - %d, act - %d, auto_change - %d, reason - %d", QSER_DATA_CALL_FUNC, pdp_data.cid, pdp_data.action, | 
 |             pdp_data.auto_change, pdp_data.reason); | 
 |      | 
 |     qser_netcard_state_init(&state); | 
 |     state.profile_idx = (char)(pdp_data.cid - 1); | 
 |     snprintf(state.name, 16, "ccinet%d", state.profile_idx); | 
 |     if(pdp_data.action) | 
 |     { | 
 |         state.state = QSER_DATA_CALL_CONNECTED; | 
 |     } | 
 |     else | 
 |     { | 
 |         state.state = QSER_DATA_CALL_DISCONNECTED; | 
 |     } | 
 |  | 
 |     if(pdp_data.ip_info_valid) | 
 |     { | 
 |         if(pdp_data.ip_info.ipv4.valid) | 
 |         { | 
 |             state.ip_family = QSER_DATA_CALL_TYPE_IPV4; | 
 |             state.v4.ip.s_addr = pdp_data.ip_info.ipv4.IPAddr; | 
 |             state.v4.pri_dns.s_addr = pdp_data.ip_info.ipv4.PrimaryDNS; | 
 |             state.v4.sec_dns.s_addr = pdp_data.ip_info.ipv4.SecondaryDNS; | 
 |         } | 
 |  | 
 |         if(pdp_data.ip_info.ipv6.valid) | 
 |         { | 
 |             state.ip_family = QSER_DATA_CALL_TYPE_IPV6; | 
 |             memcpy(&(state.v6.ip), &(pdp_data.ip_info.ipv6.IPV6Addr), sizeof(pdp_data.ip_info.ipv6.IPV6Addr)); | 
 |             memcpy(&(state.v6.pri_dns), &(pdp_data.ip_info.ipv6.PrimaryDNS), sizeof(pdp_data.ip_info.ipv6.PrimaryDNS)); | 
 |             memcpy(&(state.v6.sec_dns), &(pdp_data.ip_info.ipv6.SecondaryDNS), sizeof(pdp_data.ip_info.ipv6.SecondaryDNS)); | 
 |         } | 
 |  | 
 |         if(pdp_data.ip_info.ipv4.valid && pdp_data.ip_info.ipv6.valid) | 
 |         { | 
 |             state.ip_family = QSER_DATA_CALL_TYPE_IPV4V6; | 
 |         } | 
 |     } | 
 |  | 
 |     if(data_call_handle->net_status_cb) | 
 |     { | 
 |         data_call_handle->net_status_cb(&state); | 
 |     } | 
 | } | 
 |  | 
 | static void* qser_data_call_async_thread(void* arg) | 
 | { | 
 |     QSER_LOGD("[%s] entry func.", QSER_DATA_CALL_FUNC); | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     qser_data_call_error_e err = QSER_DATA_CALL_ERROR_NONE; | 
 |  | 
 |     qser_data_call_state_s state = {0}; | 
 |     qser_data_call_s qser_data_backup = {0}; | 
 |     qser_data_call_info_s info = {0}; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     qser_netcard_state_init(&state); | 
 |     if(arg != NULL) | 
 |     { | 
 |         memcpy(&qser_data_backup, (qser_data_call_s *)arg, sizeof(qser_data_call_s)); | 
 |     } | 
 |     else | 
 |     { | 
 |         QSER_LOGD("[%s] arg is NULL.", QSER_DATA_CALL_FUNC); | 
 |         state.err = QSER_DATA_CALL_ERROR_UNKNOWN; | 
 |         if(data_call_handle->net_status_cb) | 
 |         { | 
 |             data_call_handle->net_status_cb(&state); | 
 |         } | 
 |         return NULL; | 
 |     } | 
 |  | 
 |     state.profile_idx = qser_data_backup.profile_idx; | 
 |     snprintf(state.name, 16, "ccinet%d", qser_data_backup.profile_idx); | 
 |     state.ip_family = qser_data_backup.ip_family; | 
 |      | 
 |     ret = qser_data_call_start(&qser_data_backup, &err); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] qser_data_call_start() fail.", QSER_DATA_CALL_FUNC); | 
 |         state.err = err; | 
 |     } | 
 |     else | 
 |     { | 
 |         state.state = QSER_DATA_CALL_CONNECTED; | 
 |         ret = qser_data_call_info_get(qser_data_backup.profile_idx, qser_data_backup.ip_family, &info, &err); | 
 |         if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |         { | 
 |             QSER_LOGE("[%s] qser_data_call_info_get() fail.", QSER_DATA_CALL_FUNC); | 
 |             state.err = err; | 
 |         } | 
 |         else | 
 |         { | 
 |             memcpy(&(state.v4), &(info.v4.addr), sizeof(struct v4_address_status)); | 
 |             memcpy(&(state.v6), &(info.v6.addr), sizeof(struct v6_address_status)); | 
 |         } | 
 |     } | 
 |    | 
 |     if(data_call_handle->net_status_cb) | 
 |     { | 
 |         data_call_handle->net_status_cb(&state); | 
 |     } | 
 |     return NULL; | 
 | } | 
 |  | 
 | /*----------------------------------------------DATA CALL FUNCTION-------------------------------------*/ | 
 |  | 
 | /*----------------------------------------------DATA CALL API------------------------------------------*/ | 
 | int qser_data_call_init(qser_data_call_evt_cb_t evt_cb) | 
 | { | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle) | 
 |     { | 
 |         QSER_LOGE("[%s] qser_data_call_handle_get() fail.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |      | 
 |     if(NULL == data_call_handle->handle) | 
 |     { | 
 |         data_call_handle->handle = mbtk_ril_open(MBTK_AT_PORT_DATA); | 
 |         if(NULL == data_call_handle->handle) | 
 |         { | 
 |             QSER_LOGE("[%s] mbtk_ril_open() fail.", QSER_DATA_CALL_FUNC); | 
 |             return QSER_RESULT_FAIL; | 
 |         } | 
 |  | 
 |         ret = mbtk_pdp_state_change_cb_reg(qser_pdp_state_change_cb); | 
 |         if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |         { | 
 |             QSER_LOGE("[%s] mbtk_pdp_state_change_cb_reg() fail.[%d]", QSER_DATA_CALL_FUNC, ret); | 
 |             goto error_1; | 
 |         } | 
 |  | 
 |         data_call_handle->net_status_cb = evt_cb; | 
 |     } | 
 |      | 
 |     QSER_LOGD("[%s] data call init success.", QSER_DATA_CALL_FUNC); | 
 |      | 
 |     return QSER_RESULT_SUCCESS; | 
 | error_1: | 
 |     if(data_call_handle->handle) | 
 |     { | 
 |         ret = mbtk_ril_close(MBTK_AT_PORT_DATA); | 
 |         data_call_handle->handle = NULL; | 
 |     } | 
 |  | 
 |     return QSER_RESULT_FAIL; | 
 | } | 
 |  | 
 | void qser_data_call_destroy(void) | 
 | { | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         return; | 
 |     } | 
 |  | 
 |     data_call_handle->net_status_cb = NULL; | 
 |  | 
 |     ret = mbtk_ril_close(MBTK_AT_PORT_DATA); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS && ret != MBTK_RIL_ERR_PORT_NOT_CLOSE) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_ril_close() fail.[%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         return; | 
 |     } | 
 |     data_call_handle->handle = NULL; | 
 | } | 
 |  | 
 | int qser_data_call_start(qser_data_call_s *data_call, qser_data_call_error_e *err) | 
 | { | 
 |     if(data_call == NULL || err == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] data_call or err is NULL.", QSER_DATA_CALL_FUNC); | 
 |         if(err != NULL) | 
 |         { | 
 |             *err = QSER_DATA_CALL_ERROR_INVALID_PARAMS; | 
 |         } | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |      | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     int retry_interval[] = {5, 10}; | 
 |     mbtk_ip_info_t ip_info; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         *err = QSER_DATA_CALL_ERROR_NO_INIT; | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 |     memset(&ip_info, 0x0, sizeof(mbtk_ip_info_t)); | 
 |     ret = mbtk_data_call_start(data_call_handle->handle, (mbtk_ril_cid_enum)(data_call->profile_idx + 1), | 
 |                                 MBTK_DATA_CALL_ITEM_STATE_NON, MBTK_DATA_CALL_ITEM_STATE_NON, MBTK_DATA_CALL_ITEM_STATE_NON, | 
 |                                 retry_interval, 2, 0, &ip_info); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_data_call_start() fail.[%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         *err = QSER_DATA_CALL_ERROR_UNKNOWN; | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         *err = QSER_DATA_CALL_ERROR_NONE; | 
 |     } | 
 |  | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | int qser_data_call_start_async(qser_data_call_s *data_call, qser_data_call_error_e *err) | 
 | { | 
 |     if(data_call == NULL || err == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] data_call or err is NULL.", QSER_DATA_CALL_FUNC); | 
 |         if(err != NULL) | 
 |         { | 
 |             *err = QSER_DATA_CALL_ERROR_INVALID_PARAMS; | 
 |         } | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     pthread_attr_t thread_attr; | 
 |     pthread_t data_call_thread_id; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         *err = QSER_DATA_CALL_ERROR_NO_INIT; | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 |     pthread_attr_init(&thread_attr); | 
 |     if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED)) | 
 |     { | 
 |         QSER_LOGE("[%s] pthread_attr_setdetachstate() fail.", QSER_DATA_CALL_FUNC); | 
 |         *err = QSER_DATA_CALL_ERROR_UNKNOWN; | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     if(pthread_create(&data_call_thread_id, &thread_attr, qser_data_call_async_thread, (void *) data_call)) | 
 |     { | 
 |         QSER_LOGE("[%s] pthread_create() fail.", QSER_DATA_CALL_FUNC); | 
 |         *err = QSER_DATA_CALL_ERROR_UNKNOWN; | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     pthread_attr_destroy(&thread_attr); | 
 |      | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | int qser_data_call_stop(char profile_idx, qser_data_call_ip_family_e ip_family, qser_data_call_error_e *err) | 
 | { | 
 |     UNUSED(ip_family); | 
 |   | 
 |     if(err == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] err is NULL.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         *err = QSER_DATA_CALL_ERROR_NO_INIT; | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 |     ret = mbtk_data_call_stop(data_call_handle->handle, (mbtk_ril_cid_enum)(profile_idx + 1), 15); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_data_call_stop() fail.[%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         *err = QSER_DATA_CALL_ERROR_UNKNOWN; | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         *err = QSER_DATA_CALL_ERROR_NONE; | 
 |     } | 
 |  | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | int qser_data_call_info_get(char profile_idx,qser_data_call_ip_family_e ip_family, | 
 |         qser_data_call_info_s *info, qser_data_call_error_e *err) | 
 | { | 
 |     UNUSED(ip_family); | 
 |  | 
 |     if(info == NULL || err == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] info or err is NULL.", QSER_DATA_CALL_FUNC); | 
 |         if(err != NULL) | 
 |         { | 
 |             *err = QSER_DATA_CALL_ERROR_INVALID_PARAMS; | 
 |         } | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     mbtk_ip_info_t ip_info; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         *err = QSER_DATA_CALL_ERROR_NO_INIT; | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 | #ifdef QSER_TEST | 
 |     char v4_buff[32] = {0}; | 
 |     char v6_buff[128] = {0}; | 
 | #endif | 
 |     memset(&ip_info, 0x0, sizeof(mbtk_ip_info_t)); | 
 |     memset(info, 0x0, sizeof(qser_data_call_info_s)); | 
 |     ret = mbtk_data_call_state_get(data_call_handle->handle, (mbtk_ril_cid_enum)(profile_idx + 1), &ip_info); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_data_call_state_get fail.[%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         *err = QSER_DATA_CALL_ERROR_UNKNOWN; | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         info->profile_idx = profile_idx; | 
 |         if(ip_info.ipv4.valid) | 
 |         { | 
 |             info->ip_family = QSER_DATA_CALL_TYPE_IPV4; | 
 |             info->v4.state = QSER_DATA_CALL_CONNECTED; | 
 |             sprintf(info->v4.name, "ccinet%d", profile_idx); | 
 |             info->v4.addr.ip.s_addr = ip_info.ipv4.IPAddr; | 
 |             info->v4.addr.pri_dns.s_addr = ip_info.ipv4.PrimaryDNS; | 
 |             info->v4.addr.sec_dns.s_addr = ip_info.ipv4.SecondaryDNS; | 
 |             info->v4.reconnect = true; | 
 |  | 
 | #ifdef QSER_TEST | 
 |             //LOGE("[qser_data] IP: %x pri_DNS: %x sec_DNS: %x.", ipv4.IPAddr, ipv4.PrimaryDNS, ipv4.SecondaryDNS); | 
 |             if(inet_ntop(AF_INET, &(info->v4.addr.ip), v4_buff, 32) == NULL) { | 
 |                 LOGE("[qser_data] IP error."); | 
 |             } else { | 
 |                 LOGE("[qser_data] IP : %s", v4_buff); | 
 |             } | 
 |             if(inet_ntop(AF_INET, &(info->v4.addr.pri_dns), v4_buff, 32) == NULL) { | 
 |                 LOGE("[qser_data] PrimaryDNS error."); | 
 |             } else { | 
 |                 LOGE("[qser_data] PrimaryDNS : %s", v4_buff); | 
 |             } | 
 |             if(inet_ntop(AF_INET, &(info->v4.addr.sec_dns), v4_buff, 32) == NULL) { | 
 |                 LOGE("[qser_data] SecondaryDNS error."); | 
 |             } else { | 
 |                 LOGE("[qser_data] SecondaryDNS : %s", v4_buff); | 
 |             } | 
 | #endif | 
 |         } | 
 |  | 
 |         if(ip_info.ipv6.valid) | 
 |         { | 
 |             info->ip_family = QSER_DATA_CALL_TYPE_IPV6; | 
 |             info->v6.state = QSER_DATA_CALL_CONNECTED; | 
 |             sprintf(info->v6.name, "ccinet%d", profile_idx); | 
 |             memcpy(&(info->v6.addr.ip), &(ip_info.ipv6.IPV6Addr), sizeof(ip_info.ipv6.IPV6Addr)); | 
 |             memcpy(&(info->v6.addr.pri_dns), &(ip_info.ipv6.PrimaryDNS), sizeof(ip_info.ipv6.PrimaryDNS)); | 
 |             memcpy(&(info->v6.addr.sec_dns), &(ip_info.ipv6.SecondaryDNS), sizeof(ip_info.ipv6.SecondaryDNS)); | 
 |             info->v6.reconnect = true; | 
 |              | 
 | #ifdef QSER_TEST | 
 | 			if(ipv6_2_str(&(info->v6.addr.ip), v6_buff)) | 
 |             { | 
 | 				LOGE("[qser_data] IP error."); | 
 | 			} else { | 
 | 				LOGE("[qser_data] IP : %s", v6_buff); | 
 | 			} | 
 | 			if(ipv6_2_str(&(info->v6.addr.pri_dns), v6_buff)) | 
 |             { | 
 | 				LOGE("[qser_data] PrimaryDNS error."); | 
 | 			} else { | 
 | 				LOGE("[qser_data] PrimaryDNS : %s", v6_buff); | 
 | 			} | 
 | 			if(ipv6_2_str(&(info->v6.addr.sec_dns), v6_buff)) | 
 |             { | 
 | 				LOGE("[qser_data] SecondaryDNS error."); | 
 | 			} else { | 
 | 				LOGE("[qser_data] SecondaryDNS : %s", v6_buff); | 
 |             } | 
 | #endif | 
 |         } | 
 |          | 
 |         if(ip_info.ipv4.valid && ip_info.ipv6.valid) | 
 |         { | 
 |             info->ip_family = QSER_DATA_CALL_TYPE_IPV4V6; | 
 |         } | 
 |     } | 
 |      | 
 |     *err = QSER_DATA_CALL_ERROR_NONE; | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | int qser_apn_set(qser_apn_info_s *apn) | 
 | { | 
 |     if(apn == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] apn param is NULL.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     mbtk_apn_info_t apninfo; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 |     if(qser_apn_convert_to_mbtk_s((mbtk_ril_cid_enum)(apn->profile_idx + 1), &apninfo, apn) != QSER_RESULT_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] qser_apn_convert_to_mbtk_s() fail.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     ret = mbtk_apn_set(data_call_handle->handle, &apninfo); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_apn_set() fail.[%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | int qser_apn_get(unsigned char profile_idx, qser_apn_info_s *apn) | 
 | {     | 
 |     if(apn == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] apn param is NULL.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     int i = 0; | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     mbtk_apn_info_array_t apninfo; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 |     memset(&apninfo, 0x0, sizeof(mbtk_apn_info_array_t)); | 
 |     ret = mbtk_apn_get(data_call_handle->handle, &apninfo); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_apn_get() fail. [%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         for(i = 0; i < apninfo.num; i++) | 
 |         { | 
 |             if(apninfo.apns[i].cid == (mbtk_ril_cid_enum)(profile_idx + 1)) | 
 |             { | 
 |                 QSER_LOGD("[%s] find idx[%d].", QSER_DATA_CALL_FUNC, profile_idx); | 
 |                 break; | 
 |             } | 
 |         } | 
 |  | 
 |         if(i == apninfo.num) | 
 |         { | 
 |             QSER_LOGE("[%s] not find idx, max num[%d].", QSER_DATA_CALL_FUNC, apninfo.num); | 
 |             return QSER_RESULT_FAIL; | 
 |         } | 
 |  | 
 |         if(qser_apn_convert_to_qser_s(apn, &(apninfo.apns[i])) != QSER_RESULT_SUCCESS) | 
 |         { | 
 |             QSER_LOGE("[%s] qser_apn_convert_to_qser_s() fail.", QSER_DATA_CALL_FUNC); | 
 |             return QSER_RESULT_FAIL; | 
 |         } | 
 |     } | 
 |      | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | int qser_apn_add(qser_apn_add_s *apn, unsigned char *profile_idx) | 
 | {   | 
 |     if(apn == NULL || profile_idx == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] apn param is NULL.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     mbtk_apn_info_t apninfo; | 
 |     qser_apn_info_s qser_info; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 |     memset(&qser_info, 0x0, sizeof(qser_apn_info_s)); | 
 |     qser_info.profile_idx = MBTK_RIL_CID_NUL; | 
 |     qser_info.pdp_type = apn->pdp_type; | 
 |     qser_info.auth_proto = apn->auth_proto; | 
 |     memcpy(qser_info.apn_name, apn->apn_name, QSER_APN_NAME_SIZE); | 
 |     memcpy(qser_info.username, apn->username, QSER_APN_USERNAME_SIZE); | 
 |     memcpy(qser_info.password, apn->password, QSER_APN_PASSWORD_SIZE); | 
 |     memcpy(qser_info.apn_type, apn->apn_type, QSER_APN_TYPE_SIZE); | 
 |     if(qser_apn_convert_to_mbtk_s(MBTK_RIL_CID_NUL, &apninfo, &qser_info) != QSER_RESULT_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] apn_convert_to_mbtk_s() fail.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     ret = mbtk_apn_set(data_call_handle->handle, &apninfo); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_apn_set() fail.[%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |      | 
 |     *profile_idx = (unsigned char)(apninfo.cid - 1); | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | int qser_apn_del(unsigned char profile_idx) | 
 | { | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     mbtk_apn_info_t apninfo; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 |     memset(&apninfo, 0x0, sizeof(mbtk_apn_info_t)); | 
 |     apninfo.cid = (mbtk_ril_cid_enum)(profile_idx + 1); | 
 |     apninfo.auto_save = true; | 
 |     ret = mbtk_apn_set(data_call_handle->handle, &(apninfo)); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_apn_set fail.[%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 |  | 
 | int qser_apn_get_list(qser_apn_info_list_s *apn_list) | 
 | {   | 
 |     if(apn_list == NULL) | 
 |     { | 
 |         QSER_LOGE("[%s] apn_list param is NULL.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |  | 
 |     int i = 0; | 
 |     mbtk_ril_err_enum ret = MBTK_RIL_ERR_SUCCESS; | 
 |     mbtk_apn_info_array_t apninfo; | 
 |     qser_data_call_handle_s* data_call_handle = qser_data_call_handle_get(); | 
 |     if(NULL == data_call_handle || NULL == data_call_handle->handle) | 
 |     { | 
 |         QSER_LOGE("[%s] server not init.", QSER_DATA_CALL_FUNC); | 
 |         return QSER_RESULT_SERVER_NO_INIT; | 
 |     } | 
 |  | 
 |     memset(&apninfo, 0x0, sizeof(mbtk_apn_info_array_t)); | 
 |     ret = mbtk_apn_get(data_call_handle->handle, &apninfo); | 
 |     if(ret != MBTK_RIL_ERR_SUCCESS && ret != MBTK_RIL_ERR_CME) | 
 |     { | 
 |         QSER_LOGE("[%s] mbtk_apn_get() fail. [%d]", QSER_DATA_CALL_FUNC, ret); | 
 |         return QSER_RESULT_FAIL; | 
 |     } | 
 |     else | 
 |     { | 
 |         if(apninfo.num > 0 && apninfo.num <= QSER_APN_MAX_LIST) | 
 |         { | 
 |             apn_list->cnt = 0; | 
 |             for(i = 0; i < apninfo.num; i++) | 
 |             { | 
 |                 if(qser_apn_convert_to_qser_s(&apn_list->apn[apn_list->cnt], &(apninfo.apns[i])) != QSER_RESULT_SUCCESS) | 
 |                 { | 
 |                     QSER_LOGE("[%s] qser_apn_convert_to_qser_s() fail.", QSER_DATA_CALL_FUNC); | 
 |                     return QSER_RESULT_FAIL; | 
 |                 } | 
 |                 apn_list->cnt++; | 
 |             } | 
 |         } | 
 |         else if(apninfo.num > QSER_APN_MAX_LIST) | 
 |         { | 
 |             QSER_LOGE("[%s] apn_num overlong.", QSER_DATA_CALL_FUNC); | 
 |             return QSER_RESULT_FAIL; | 
 |         } | 
 |         else | 
 |         { | 
 |             apn_list->cnt = 0; | 
 |         } | 
 |     } | 
 |      | 
 |     return QSER_RESULT_SUCCESS; | 
 | } | 
 | /*----------------------------------------------DATA CALL API------------------------------------------*/ | 
 |  |