Add basic change for v1453

Change-Id: I9497a61bbc3717f66413794a4e7dee0347c0bc33
diff --git a/mbtk/liblynq_lib_rilv2/lynq_data_call.c b/mbtk/liblynq_lib_rilv2/lynq_data_call.c
new file mode 100755
index 0000000..94bf008
--- /dev/null
+++ b/mbtk/liblynq_lib_rilv2/lynq_data_call.c
@@ -0,0 +1,892 @@
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @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------------------------------------------*/
+