Add basic change for v1453

Change-Id: I9497a61bbc3717f66413794a4e7dee0347c0bc33
diff --git a/mbtk/libql_lib_v2_rilv2/ql_data_call.c b/mbtk/libql_lib_v2_rilv2/ql_data_call.c
new file mode 100755
index 0000000..0f18e77
--- /dev/null
+++ b/mbtk/libql_lib_v2_rilv2/ql_data_call.c
@@ -0,0 +1,1621 @@
+#include "ql_type.h"
+#include "ql_data_call.h"
+#include "mbtk_info_api.h"
+
+typedef struct {
+    int apn_id;
+    ql_data_call_apn_config_t apn_info;
+} mbtk_data_call_apn_param_info_t;
+
+typedef struct {
+    QL_NET_DATA_CALL_RECONNECT_MODE_E reconnect_mode;
+    int time_num;
+    int time_list[QL_NET_MAX_RECONNECT_INTERVAL_LEN];
+    mbtk_data_call_apn_param_info_t *apn_param;     // Point to data_call_apn_param_list.
+} mbtk_data_call_param_info_t;
+
+typedef struct {
+    ql_data_call_item_t call_info;
+    int is_background;
+
+    ql_data_call_status_t call_state;
+
+    mbtk_data_call_param_info_t call_param_info;
+} mbtk_data_call_info_t;
+
+static mbtk_info_handle_t* ql_info_handle = NULL;
+static mbtk_data_call_info_t data_call_info[QL_NET_MAX_DATA_CALL_NUM];
+static mbtk_data_call_apn_param_info_t data_call_apn_param_list[QL_NET_MAX_DATA_CALL_NUM];
+static ql_data_call_service_error_cb_f data_call_service_error_cb = NULL;
+static ql_data_call_status_ind_cb_f data_call_status_ind_cb = NULL;
+
+static int call_index_get_by_call_id(int call_id)
+{
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id == call_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) {
+        return -1;
+    } else {
+        return i;
+    }
+}
+
+static int call_index_get_by_apn_id(int apn_id)
+{
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_param_info.apn_param &&
+            data_call_info[i].call_param_info.apn_param->apn_id == apn_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) {
+        return -1;
+    } else {
+        return i;
+    }
+}
+
+static void data_call_info_list_print()
+{
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id > 0) {
+            LOGD("CALL START : call_id - %d, call_name - %s, is_background - %d", data_call_info[i].call_info.call_id, data_call_info[i].call_info.call_name,
+                data_call_info[i].is_background);
+            LOGD("call_state : ip_ver - %d, call_status - %d, device - %s", data_call_info[i].call_state.ip_ver,
+            data_call_info[i].call_state.call_status, data_call_info[i].call_state.device);
+            LOGD("param_info : reconnect_mode - %d, time_num - %d", data_call_info[i].call_param_info.reconnect_mode,
+                data_call_info[i].call_param_info.time_num);
+            int j = 0;
+            while(j < data_call_info[i].call_param_info.time_num) {
+                LOGD("time_item[%d] - %d", j, data_call_info[i].call_param_info.time_list[j]);
+                j++;
+            }
+
+            if(data_call_info[i].call_param_info.apn_param) {
+                LOGD("apn_param : apn_id - %d, auth_pref - %d, ip_ver - %d, apn_name - %s, username - %s, password - %s", data_call_info[i].call_param_info.apn_param->apn_id,
+                    data_call_info[i].call_param_info.apn_param->apn_info.auth_pref,
+                    data_call_info[i].call_param_info.apn_param->apn_info.ip_ver,
+                    data_call_info[i].call_param_info.apn_param->apn_info.apn_name,
+                    data_call_info[i].call_param_info.apn_param->apn_info.username,
+                    data_call_info[i].call_param_info.apn_param->apn_info.password);
+            } else {
+                LOGE("data_call_info[i]->call_param_info->apn_param is NULL.");
+            }
+        }
+        i++;
+    }
+}
+
+static void data_call_info_item_print(int call_id)
+{
+    int i = call_index_get_by_call_id(call_id);
+    if(i >= 0) {
+        LOGD("CALL START : call_id - %d, call_name - %s, is_background - %d", data_call_info[i].call_info.call_id, data_call_info[i].call_info.call_name,
+            data_call_info[i].is_background);
+        LOGD("call_state : ip_ver - %d, call_status - %d, device - %s", data_call_info[i].call_state.ip_ver,
+        data_call_info[i].call_state.call_status, data_call_info[i].call_state.device);
+        LOGD("param_info : reconnect_mode - %d, time_num - %d", data_call_info[i].call_param_info.reconnect_mode,
+            data_call_info[i].call_param_info.time_num);
+        int j = 0;
+        while(j < data_call_info[i].call_param_info.time_num) {
+            LOGD("time_item[%d] - %d", j, data_call_info[i].call_param_info.time_list[j]);
+            j++;
+        }
+
+        if(data_call_info[i].call_param_info.apn_param) {
+            LOGD("apn_param : apn_id - %d, auth_pref - %d, ip_ver - %d, apn_name - %s, username - %s, password - %s", data_call_info[i].call_param_info.apn_param->apn_id,
+                data_call_info[i].call_param_info.apn_param->apn_info.auth_pref,
+                data_call_info[i].call_param_info.apn_param->apn_info.ip_ver,
+                data_call_info[i].call_param_info.apn_param->apn_info.apn_name,
+                data_call_info[i].call_param_info.apn_param->apn_info.username,
+                data_call_info[i].call_param_info.apn_param->apn_info.password);
+        } else {
+            LOGE("data_call_info[i]->call_param_info->apn_param is NULL.");
+        }
+    }
+}
+
+
+static void ril_server_state_cb(const void* data, int data_len)
+{
+    if(data != NULL && data_len == sizeof(int)) {
+        const int *state = (const int*)data;
+        if(*state) {
+            if(data_call_service_error_cb) {
+                data_call_service_error_cb(QL_ERR_ABORTED);
+            }
+        }
+    }
+}
+
+static void data_call_state_change_cb(const void* data, int data_len)
+{
+    LOGD("data_call_state_change_cb() start.");
+    if(data == NULL || data_len == 0)
+    {
+        return;
+    }
+
+    // data_call_info_print();
+
+    uint8 *net_data = NULL;
+    net_data = (uint8 *)data;
+
+    if(*net_data > 100 && *net_data < 200)
+    {
+        int apn_id = *net_data - 100;
+        if(apn_id <= QL_NET_MAX_DATA_CALL_NUM)
+        {
+            int i = 0;
+            while(i < QL_NET_MAX_DATA_CALL_NUM) {
+
+                if(data_call_info[i].call_param_info.apn_param) {
+                    if(data_call_info[i].call_param_info.apn_param->apn_id == apn_id) {
+                        break;
+                    } else {
+                        LOGD("call_id = %d, apn_id = %d", data_call_info[i].call_info.call_id,
+                            data_call_info[i].call_param_info.apn_param->apn_id);
+                    }
+                }
+                i++;
+            }
+
+            if(i == QL_NET_MAX_DATA_CALL_NUM) { // No found this apn_id.
+                LOGW("Unknown apn_id : %d", apn_id);
+                return;
+            } else {
+                QL_NET_DATA_CALL_STATUS_E pre_call_status = data_call_info[i].call_state.call_status;
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_DISCONNECTED;
+                if(data_call_status_ind_cb) {
+                    data_call_status_ind_cb(data_call_info[i].call_info.call_id, pre_call_status,
+                        &(data_call_info[i].call_state));
+                }
+            }
+        }
+        else
+        {
+            LOGE("[qser_data] cb fail,idx is %d.", apn_id);
+        }
+
+    }
+    else if(*net_data > 200 && *net_data < 220)
+    {
+        LOGE("[qser_data] cid[%d] is open.", *net_data - 200);
+    }
+    else if(*net_data > 220)
+    {
+        LOGE("[qser_data] cid[%d] is reopen.", *net_data - 220);
+        int apn_id = *net_data - 220;
+        if(apn_id <= QL_NET_MAX_DATA_CALL_NUM)
+        {
+            int i = 0;
+            while(i < QL_NET_MAX_DATA_CALL_NUM) {
+                if(data_call_info[i].call_param_info.apn_param
+                    && data_call_info[i].call_param_info.apn_param->apn_id == apn_id) {
+                    break;
+                }
+                i++;
+            }
+
+            if(i == QL_NET_MAX_DATA_CALL_NUM) { // No found this apn_id.
+                LOGW("Unknown apn_id : %d", apn_id);
+                return;
+            } else {
+                QL_NET_DATA_CALL_STATUS_E pre_call_status = data_call_info[i].call_state.call_status;
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_CONNECTED;
+                if(data_call_status_ind_cb) {
+                    data_call_status_ind_cb(data_call_info[i].call_info.call_id, pre_call_status,
+                        &(data_call_info[i].call_state));
+                }
+            }
+        }
+    }
+    else if(*net_data == 1)
+    {
+        LOGE("[qser_data] pdp is open.");
+    }
+    else
+    {
+        LOGE("[qser_data] unkonwn param [%d].", *net_data);
+    }
+}
+
+static int data_call_state_query(int call_id)
+{
+    int i = call_index_get_by_call_id(call_id);
+    if(i < 0) {
+        LOGE("Unknown call_id : %d", call_id);
+        return -1;
+    }
+
+    // Get network information.
+    mbtk_ipv4_info_t ipv4;
+    mbtk_ipv6_info_t ipv6;
+    QL_NET_DATA_CALL_STATUS_E pre_call_status = data_call_info[i].call_state.call_status;
+    int ret = mbtk_data_call_state_get(ql_info_handle, data_call_info[i].call_param_info.apn_param->apn_id, &ipv4, &ipv6);
+    if(ret != 0)
+    {
+        LOGE("mbtk_data_call_state_get fail.[ret = %d]", ret);
+        data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_ERROR;
+        return -1;
+    }
+    else
+    {
+        data_call_info[i].call_state.has_addr = ipv4.valid;
+        if(ipv4.valid)
+        {
+            if(inet_ntop(AF_INET, &(ipv4.IPAddr), data_call_info[i].call_state.addr.addr , QL_NET_MAX_ADDR_LEN) == NULL) {
+                LOGE("IPv4 error.");
+            } else {
+                LOGD("IPv4 : %s", data_call_info[i].call_state.addr.addr);
+            }
+
+            if(inet_ntop(AF_INET, &(ipv4.NetMask), data_call_info[i].call_state.addr.netmask , QL_NET_MAX_ADDR_LEN) == NULL) {
+                LOGE("NetMask error.");
+            } else {
+                LOGD("NetMask : %s", data_call_info[i].call_state.addr.netmask);
+            }
+
+            if(inet_ntop(AF_INET, &(ipv4.GateWay), data_call_info[i].call_state.addr.gateway , QL_NET_MAX_ADDR_LEN) == NULL) {
+                LOGE("GateWay error.");
+            } else {
+                LOGD("GateWay : %s", data_call_info[i].call_state.addr.gateway);
+            }
+
+            if(inet_ntop(AF_INET, &(ipv4.PrimaryDNS), data_call_info[i].call_state.addr.dnsp , QL_NET_MAX_ADDR_LEN) == NULL) {
+                LOGE("PrimaryDNS error.");
+            } else {
+                LOGD("PrimaryDNS : %s", data_call_info[i].call_state.addr.dnsp);
+            }
+
+            if(inet_ntop(AF_INET, &(ipv4.SecondaryDNS), data_call_info[i].call_state.addr.dnss , QL_NET_MAX_ADDR_LEN) == NULL) {
+                LOGE("SecondaryDNS error.");
+            } else {
+                LOGD("SecondaryDNS : %s", data_call_info[i].call_state.addr.dnss);
+            }
+        }
+
+        data_call_info[i].call_state.has_addr6 = ipv6.valid;
+        if(ipv6.valid)
+        {
+            if(ipv6_2_str(&(ipv6.IPV6Addr), data_call_info[i].call_state.addr6.addr)) {
+                LOGE("IPv6 error.");
+            } else {
+                LOGD("IPv6 : %s", data_call_info[i].call_state.addr6.addr);
+            }
+
+            if(ipv6_2_str(&(ipv6.NetMask), data_call_info[i].call_state.addr6.prefix)) {
+                LOGE("prefix error.");
+            } else {
+                LOGD("prefix : %s", data_call_info[i].call_state.addr6.prefix);
+            }
+
+            if(ipv6_2_str(&(ipv6.GateWay), data_call_info[i].call_state.addr6.gateway)) {
+                LOGE("GateWay error.");
+            } else {
+                LOGD("GateWay : %s", data_call_info[i].call_state.addr6.gateway);
+            }
+
+            if(ipv6_2_str(&(ipv6.PrimaryDNS), data_call_info[i].call_state.addr6.dnsp)) {
+                LOGE("PrimaryDNS error.");
+            } else {
+                LOGD("PrimaryDNS : %s", data_call_info[i].call_state.addr6.dnsp);
+            }
+
+            if(ipv6_2_str(&(ipv6.SecondaryDNS), data_call_info[i].call_state.addr6.dnsp)) {
+                LOGE("SecondaryDNS error.");
+            } else {
+                LOGD("SecondaryDNS : %s", data_call_info[i].call_state.addr6.dnsp);
+            }
+        }
+
+        pre_call_status = data_call_info[i].call_state.call_status;
+#if 1
+        if(data_call_info[i].call_state.ip_ver == QL_NET_IP_VER_V4V6) {
+            if(ipv4.valid && !ipv6.valid) {
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_PARTIAL_V4_CONNECTED;
+            } else if(!ipv4.valid && ipv6.valid) {
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_PARTIAL_V6_CONNECTED;
+            } else if(ipv4.valid && ipv6.valid) {
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_CONNECTED;
+            } else {
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_DISCONNECTED;
+            }
+        } else if(data_call_info[i].call_state.ip_ver == QL_NET_IP_VER_V4) {
+            if(ipv4.valid) {
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_CONNECTED;
+            } else {
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_DISCONNECTED;
+            }
+        } else if(data_call_info[i].call_state.ip_ver == QL_NET_IP_VER_V6) {
+            if(ipv6.valid) {
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_CONNECTED;
+            } else {
+                data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_DISCONNECTED;
+            }
+        } else {
+            data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_DISCONNECTED;
+        }
+#else
+        if(ipv4.valid && ipv6.valid) {
+            data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_CONNECTED;
+        } else if(!ipv4.valid && ipv6.valid) {
+            data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_PARTIAL_V6_CONNECTED;
+        } else if(ipv4.valid && !ipv6.valid) {
+            data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_PARTIAL_V4_CONNECTED;
+        } else {
+            data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_DISCONNECTED;
+        }
+#endif
+
+        if(data_call_status_ind_cb) {
+            data_call_status_ind_cb(call_id, pre_call_status,
+                &(data_call_info[i].call_state));
+        }
+    }
+
+    return 0;
+}
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Initialize the data call service
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_INVALID_ARG - as defined
+  QL_ERR_UNKNOWN - unknown error, failed to connect to service
+  QL_ERR_SERVICE_NOT_READY - service is not ready, need to retry
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_init(void)
+{
+    if(ql_info_handle == NULL)
+    {
+
+        mbtk_log_init("radio", "QL_DATA_CALL");
+
+        ql_info_handle = mbtk_info_handle_get();
+        if(ql_info_handle)
+        {
+            memset(&data_call_info, 0, sizeof(data_call_info));
+            memset(&data_call_apn_param_list, 0, sizeof(data_call_apn_param_list));
+            return QL_ERR_OK;
+        } else {
+            LOGE("mbtk_info_handle_get() fail.");
+            return QL_ERR_UNKNOWN;
+        }
+    } else {
+        return QL_ERR_UNKNOWN;
+    }
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Create a data call instance
+  @param[in] call_id The unique identifier of the data call instance, specified by the user
+  @param[in] call_name Friendly data call name,  specified by the user
+  @param[in] is_background Whether the data call status is maintained by the data call service daemon.
+  If it is 0, the data call instance will be deleted after the data call process exits.
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_INVALID_ARG - as defined
+  QL_ERR_UNKNOWN - unknown error, failed to connect to service
+  QL_ERR_SERVICE_NOT_READY - service is not ready, need to retry
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_create(int call_id, const char *call_name, int is_background)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(call_id <= 0 || call_name == NULL || strlen(call_name) == 0
+        || strlen(call_name) > QL_NET_MAX_NAME_LEN) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id == 0) { // Not use.
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) { // data_call item full.
+        LOGW("data_call instance is full.");
+        return QL_ERR_UNKNOWN;
+    }
+
+    data_call_info[i].call_info.call_id = call_id;
+    memcpy(data_call_info[i].call_info.call_name, call_name, strlen(call_name));
+    data_call_info[i].call_state.call_id = call_id;
+    memcpy(data_call_info[i].call_state.call_name, call_name, strlen(call_name));
+
+    data_call_info[i].is_background = is_background;
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Alloc for a data call configuration instance
+  @return
+  NULL - Not enough memory
+  Other - successful
+  */
+/*-----------------------------------------------------------------------------------------------*/
+ql_data_call_param_t *ql_data_call_param_alloc(void)
+{
+    ql_data_call_param_t *result = malloc(sizeof(mbtk_data_call_param_info_t));
+    if(result) {
+        memset(result, 0, sizeof(mbtk_data_call_param_info_t));
+    }
+
+    return result;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Initialize the data call configuration instance
+  @param[in] param Point to the data call configuration instance
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_init(ql_data_call_param_t *param)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    memset(info, 0, sizeof(mbtk_data_call_param_info_t));
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Release the data call configuration instance
+  @param[in] param Point to the data call configuration instance
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_free(ql_data_call_param_t *param)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    free(param);
+
+    return QL_ERR_OK;
+}
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Bind APN ID, range:1-16
+  @param[in] param Point to the data call configuration instance
+  @param[in] apn_id APN ID, range:1-16
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_set_apn_id(ql_data_call_param_t *param, int apn_id)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    // 1 - 7
+    if(param == NULL || apn_id <= 0 || apn_id > QL_NET_MAX_APN_ID) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_apn_param_list[i].apn_id == apn_id) {
+            break;
+        }
+        i++;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param != NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    if(i == QL_NET_MAX_DATA_CALL_NUM) {
+        LOGW("No found apn_id : %d.", apn_id);
+        // Found next empty apn item.
+        int j = 0;
+        while(j < QL_NET_MAX_DATA_CALL_NUM) {
+            if(data_call_apn_param_list[j].apn_id <= 0) {
+                break;
+            }
+            j++;
+        }
+        if(j == QL_NET_MAX_DATA_CALL_NUM) { // Full
+            return QL_ERR_UNKNOWN;
+        }
+
+        info->apn_param = &(data_call_apn_param_list[j]);
+        info->apn_param->apn_id = apn_id;
+    } else {
+        // Found apn_id
+        info->apn_param = &(data_call_apn_param_list[i]);
+    }
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get APN name from configuration instance
+  @param[in] param Point to the data call configuration instance
+  @param[out] buf APN ID
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_get_apn_id(ql_data_call_param_t *param, int *apn_id)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || apn_id == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    *apn_id = info->apn_param->apn_id;
+
+    return QL_ERR_OK;
+}
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure APN name
+  @param[in] param Point to the data call configuration instance
+  @param[in] apn_name APN name
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_set_apn_name(ql_data_call_param_t *param, const char *apn_name)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || apn_name == NULL || strlen(apn_name) == 0
+        || strlen(apn_name) > QL_NET_MAX_APN_NAME_LEN) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    memcpy(info->apn_param->apn_info.apn_name, apn_name, strlen(apn_name));
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get APN name from configuration instance
+  @param[in] param Point to the data call configuration instance
+  @param[out] buf APN name buffer
+  @param[in] buf_len APN name buffer size
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_get_apn_name(ql_data_call_param_t *param, char *buf, int buf_len)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || buf == NULL || buf_len <= 0) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    if(strlen(info->apn_param->apn_info.apn_name) + 1 > buf_len) {
+        return QL_ERR_INVALID_ARG;
+    }
+    memcpy(buf, info->apn_param->apn_info.apn_name, strlen(info->apn_param->apn_info.apn_name));
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure APN user name
+  @param[in] param Point to the data call configuration instance
+  @param[in] user_name APN user name
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_set_user_name(ql_data_call_param_t *param, const char *user_name)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || user_name == NULL || strlen(user_name) == 0
+        || strlen(user_name) > QL_NET_MAX_APN_USERNAME_LEN) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    memcpy(info->apn_param->apn_info.username, user_name, strlen(user_name));
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get APN user name from configuration instance
+  @param[in] param Point to the data call configuration instance
+  @param[out] buf APN user name buffer
+  @param[in] buf_len APN user name buffer size
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_get_user_name(ql_data_call_param_t *param, char *buf, int buf_len)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || buf == NULL || buf_len <= 0) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    if(strlen(info->apn_param->apn_info.username) + 1 > buf_len) {
+        return QL_ERR_INVALID_ARG;
+    }
+    memcpy(buf, info->apn_param->apn_info.username, strlen(info->apn_param->apn_info.username));
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure APN user password
+  @param[in] param Point to the data call configuration instance
+  @param[in] user_password APN user password
+  @return
+  QL_ERR_OK - Not enough memory
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_set_user_password(ql_data_call_param_t *param, const char *user_password)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || user_password == NULL || strlen(user_password) == 0
+        || strlen(user_password) > QL_NET_MAX_APN_PASSWORD_LEN) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    memcpy(info->apn_param->apn_info.password, user_password, strlen(user_password));
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get APN user password from configuration instance
+  @param[in] param Point to the data call configuration instance
+  @param[out] buf APN user password buffer
+  @param[in] buf_len APN user password buffer size
+  @return
+  QL_ERR_OK - Not enough memory
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_get_user_password(ql_data_call_param_t *param, char *buf, int buf_len)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || buf == NULL || buf_len <= 0) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    if(strlen(info->apn_param->apn_info.password) + 1 > buf_len) {
+        return QL_ERR_INVALID_ARG;
+    }
+    memcpy(buf, info->apn_param->apn_info.password, strlen(info->apn_param->apn_info.password));
+
+    return QL_ERR_OK;
+}
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure the data call authentication method
+  @param[in] param Point to the data call configuration instance
+  @param[in] auth_pref Defined by QL_DATA_CALL_AUTH_PREF_E
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_set_auth_pref(ql_data_call_param_t *param, int auth_pref)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    info->apn_param->apn_info.auth_pref = (QL_NET_AUTH_PREF_E)auth_pref;
+
+    return QL_ERR_OK;
+
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure the data call authentication method
+  @param[in] param Point to the data call configuration instance
+  @param[out] p_data Store return value
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_get_auth_pref(ql_data_call_param_t *param, int *p_data)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || p_data == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    *p_data = info->apn_param->apn_info.auth_pref;
+
+    return QL_ERR_OK;
+}
+
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure the data call IP version
+  @param[in] param Point to the data call configuration instance
+  @param[in] ip_ver Defined by QL_NET_IP_VER_E
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_set_ip_version(ql_data_call_param_t *param, int ip_ver)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    info->apn_param->apn_info.ip_ver = (QL_NET_IP_VER_E)ip_ver;
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get IP version from configuration instance
+  @param[in] param Point to the data call configuration instance
+  @param[out] p_ver Store return value
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_get_ip_version(ql_data_call_param_t *param, int *p_ver)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || p_ver == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    if(info->apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    *p_ver = info->apn_param->apn_info.ip_ver;
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure the data call auto reconnection mode
+  @param[in] param Point to the data call configuration instance
+  @param[in] mode Defined by QL_NET_DATA_CALL_RECONNECT_MODE_E
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_set_reconnect_mode(ql_data_call_param_t *param, int reconnect_mode)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    info->reconnect_mode = reconnect_mode;
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get auto reconnection mode from configuration instance
+  @param[in] param Point to the data call configuration instance
+  @param[out] p_mode Store return value
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_get_reconnect_mode(ql_data_call_param_t *param, int *p_mode)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || p_mode == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    *p_mode = info->reconnect_mode;
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure the data call auto reconnection interval
+  @param[in] param Point to the data call configuration instance
+  @param[in] time_list Interval time list in ms
+  @param[in] num Number of time list
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_set_reconnect_interval(ql_data_call_param_t *param, int *time_list, int num)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || time_list == NULL || num <= 0 || num > QL_NET_MAX_RECONNECT_INTERVAL_LEN) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    info->time_num = num;
+    memcpy(&(info->time_list), time_list, sizeof(int) * num);
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get auto reconnection interval from configuration instance
+  @param[in] param Point to the data call configuration instance
+  @param[out] time_list Store return value
+  @param[in,out] p_num
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_param_get_reconnect_interval(ql_data_call_param_t *param, int *time_list, int *p_num)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL || time_list == NULL || p_num == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    mbtk_data_call_param_info_t *info = (mbtk_data_call_param_info_t*)param;
+    *p_num = info->time_num;
+    int i = 0;
+    for(; i < info->time_num; i++) {
+        *(time_list + i) = info->time_list[i];
+    }
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Configure the specified data call instance
+  @param[in] call_id Specify a data call instance
+  @param[in] param Point to the data call configuration instance
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_config(int call_id, ql_data_call_param_t *param)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id == call_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) { // No found this call_id.
+        LOGW("Unknown call_id : %d", call_id);
+        return QL_ERR_UNKNOWN;
+    }
+
+    memcpy(&(data_call_info[i].call_param_info), param, sizeof(mbtk_data_call_param_info_t));;
+
+    if(data_call_info[i].call_param_info.apn_param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+    snprintf(data_call_info[i].call_state.device, QL_NET_MAX_NAME_LEN, "ccinet%d",
+        data_call_info[i].call_param_info.apn_param->apn_id - 1);
+    data_call_info[i].call_state.ip_ver = data_call_info[i].call_param_info.apn_param->apn_info.ip_ver;
+    data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_IDLE;
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get the specified data call configuration instance
+  @param[in] call_id Specify a data call instance
+  @param[in] param Point to the data call configuration instance
+  @return
+  QL_ERR_OK - Successful
+  QL_ERR_INVALID_ARG - Invalid arguments
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_get_config(int call_id, ql_data_call_param_t *param)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(param == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id == call_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) { // No found this call_id.
+        LOGW("Unknown call_id : %d", call_id);
+        return QL_ERR_UNKNOWN;
+    }
+
+    memcpy(param, &(data_call_info[i].call_param_info), sizeof(mbtk_data_call_param_info_t));
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Start data call
+  @param[in] call_id Specify a data call instance
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_start(int call_id)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    int i = call_index_get_by_call_id(call_id);
+    if(i < 0) {
+        LOGE("Unknown call_id : %d", call_id);
+        return QL_ERR_UNKNOWN;
+    }
+
+    if(data_call_info[i].call_param_info.apn_param == NULL) {
+        LOGE("data_call_info[i]->call_param_info->apn_param is NULL.");
+        return QL_ERR_UNKNOWN;
+    }
+
+    int ret = data_call_state_query(call_id);
+    if(ret) {
+        LOGE("data_call_state_query fail.");
+        data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_IDLE;
+        // return QL_ERR_UNKNOWN;
+    }
+
+    if(data_call_info[i].call_state.call_status == QL_NET_DATA_CALL_STATUS_PARTIAL_V4_CONNECTED
+        || data_call_info[i].call_state.call_status == QL_NET_DATA_CALL_STATUS_PARTIAL_V6_CONNECTED
+        || data_call_info[i].call_state.call_status == QL_NET_DATA_CALL_STATUS_CONNECTED) {
+        LOGW("call_id %d has connected.", call_id);
+        return QL_ERR_UNKNOWN;
+    }
+
+    LOGD("Start Data Call : %d", call_id);
+    data_call_info_item_print(call_id);
+
+    // Set APN in the first.
+    mbtk_ip_type_enum ip_type;
+    switch(data_call_info[i].call_param_info.apn_param->apn_info.ip_ver) {
+        case QL_NET_IP_VER_V4:
+            ip_type = MBTK_IP_TYPE_IP;
+            break;
+        case QL_NET_IP_VER_V6:
+            ip_type = MBTK_IP_TYPE_IPV6;
+            break;
+        case QL_NET_IP_VER_V4V6:
+            ip_type = MBTK_IP_TYPE_IPV4V6;
+            break;
+        default:
+            LOGE("Unknown ip_ver.");
+            return QL_ERR_UNKNOWN;
+    }
+
+    char auth_type[64]={0};
+    switch(data_call_info[i].call_param_info.apn_param->apn_info.auth_pref) {
+        case QL_NET_AUTH_PREF_PAP_CHAP_NOT_ALLOWED:
+            memcpy(auth_type,"NONE",strlen("NONE"));
+            break;
+        case QL_NET_AUTH_PREF_PAP_ONLY_ALLOWED:
+            memcpy(auth_type,"PAP",strlen("PAP"));
+            break;
+        case QL_NET_AUTH_PREF_CHAP_ONLY_ALLOWED:
+            memcpy(auth_type,"CHAP",strlen("CHAP"));
+            break;
+#if 0
+        case QL_NET_AUTH_PREF_PAP_CHAP_BOTH_ALLOWED:
+            apninfo.auth_proto = MBTK_APN_AUTH_PROTO_PAP_CHAP;
+            break;
+#endif
+        default:
+            LOGE("Unknown auth_pref.");
+            return QL_ERR_UNKNOWN;
+    }
+
+    ret = mbtk_apn_set(ql_info_handle, data_call_info[i].call_param_info.apn_param->apn_id, ip_type,
+                data_call_info[i].call_param_info.apn_param->apn_info.apn_name,
+                data_call_info[i].call_param_info.apn_param->apn_info.username,
+                data_call_info[i].call_param_info.apn_param->apn_info.password, auth_type);
+    if(ret) {
+        LOGE("mbtk_apn_set fail.");
+        return QL_ERR_UNKNOWN;
+    }
+
+    // Start data call.
+    int auto_conn_interval = 0;
+    QL_NET_DATA_CALL_STATUS_E pre_call_status = data_call_info[i].call_state.call_status;
+    data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_CONNECTING;
+    if(data_call_status_ind_cb) {
+        data_call_status_ind_cb(call_id, pre_call_status,
+            &(data_call_info[i].call_state));
+    }
+
+    if(data_call_info[i].call_param_info.reconnect_mode == QL_NET_DATA_CALL_RECONNECT_NORMAL
+        || data_call_info[i].call_param_info.reconnect_mode == QL_NET_DATA_CALL_RECONNECT_MODE_1
+        || data_call_info[i].call_param_info.reconnect_mode == QL_NET_DATA_CALL_RECONNECT_MODE_2) {
+        if(data_call_info[i].call_param_info.time_num > 0) {
+            auto_conn_interval = data_call_info[i].call_param_info.time_list[0];
+        }
+    } else {
+        auto_conn_interval = 0;
+    }
+
+    ret = mbtk_data_call_start(ql_info_handle, data_call_info[i].call_param_info.apn_param->apn_id, auto_conn_interval,
+                FALSE, 0);
+    if(ret) {
+        LOGE("mbtk_data_call_start fail.");
+        data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_ERROR;
+        return QL_ERR_UNKNOWN;
+    }
+
+    ret = data_call_state_query(call_id);
+    if(ret) {
+        LOGE("data_call_state_query fail.");
+        data_call_info[i].call_state.call_status = QL_NET_DATA_CALL_STATUS_ERROR;
+        return QL_ERR_UNKNOWN;
+    }
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Stop data call
+  @param[in] call_id Specify a data call instance
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_stop(int call_id)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id == call_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(data_call_info[i].call_param_info.apn_param) {
+        int ret = mbtk_data_call_stop(ql_info_handle, data_call_info[i].call_param_info.apn_param->apn_id, 15);
+        if(ret) {
+            LOGE("mbtk_data_call_stop() fail.");
+            return QL_ERR_UNKNOWN;
+        }
+    } else {
+        LOGE("data_call_info[i]->call_param_info->apn_param is NULL.");
+        return QL_ERR_UNKNOWN;
+    }
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Delete a data call instance
+  @param[in] call_id Specify a data call instance
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_delete(int call_id)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id == call_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) { // No found this call_id.
+        LOGW("Unknown call_id : %d", call_id);
+        return QL_ERR_UNKNOWN;
+    }
+
+    if(data_call_info[i].call_param_info.apn_param) {
+        memset(data_call_info[i].call_param_info.apn_param, 0, sizeof(mbtk_data_call_apn_param_info_t));
+    }
+    memset(&(data_call_info[i]), 0, sizeof(mbtk_data_call_info_t));
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get the current data call instance list
+  @param[out] list Data call instance array
+  @param[in,out] list_len, in-> Data call instance array size, out->current data call instance number
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_get_list(ql_data_call_item_t *list, int *list_len)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(list == NULL || list_len == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    int i = 0;
+    *list_len = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id > 0) {
+            memset(&(list[*list_len]), 0, sizeof(ql_data_call_item_t));
+            list[*list_len].call_id = data_call_info[i].call_info.call_id;
+            memcpy(list[*list_len].call_name, data_call_info[i].call_info.call_name,
+                strlen(data_call_info[i].call_info.call_name));
+
+            (*list_len)++;
+        }
+        i++;
+    }
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Get the data call status
+  @param[in] call_id Specify a data call instance
+  @param[out] p_sta Point to status instance
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_get_status(int call_id, ql_data_call_status_t *p_sta)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(p_sta == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_info.call_id == call_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) { // No found this call_id.
+        LOGW("Unknown call_id : %d", call_id);
+        return QL_ERR_UNKNOWN;
+    }
+
+    memcpy(p_sta, &(data_call_info[i].call_state), sizeof(ql_data_call_status_t));
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Register data call status change event
+  @param[in] cb
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_set_status_ind_cb(ql_data_call_status_ind_cb_f cb)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_UNKNOWN;
+    } else {
+        if(mbtk_pdp_state_change_cb_reg(ql_info_handle, data_call_state_change_cb))
+        {
+            return QL_ERR_UNKNOWN;
+        }
+
+        data_call_status_ind_cb = cb;
+        return QL_ERR_OK;
+    }
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Set APN related configuration.If the apn does not exist, it is automatically created.
+  @param[in] apn_id APN ID, range:1-16
+  @param[in] p_info APN configuration
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_set_apn_config(int apn_id, ql_data_call_apn_config_t *p_info)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(p_info == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_param_info.apn_param
+            && data_call_info[i].call_param_info.apn_param->apn_id == apn_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) { // No found this apn_id.
+        LOGW("New apn_id : %d", apn_id);
+        // New data call param.
+        int j = 0;
+        while(j < QL_NET_MAX_DATA_CALL_NUM) {
+            if(data_call_apn_param_list[j].apn_id <= 0) {
+                break;
+            }
+            j++;
+        }
+
+        if(j == QL_NET_MAX_DATA_CALL_NUM) { // Full
+            LOGW("data_call_apn_param_list is full.");
+            return QL_ERR_UNKNOWN;
+        }
+
+        data_call_apn_param_list[j].apn_id = apn_id;
+        memcpy(&(data_call_apn_param_list[j].apn_info), p_info, sizeof(ql_data_call_apn_config_t));
+    } else {
+        memcpy(&(data_call_info[i].call_param_info.apn_param->apn_info), p_info, sizeof(ql_data_call_apn_config_t));
+    }
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief  Set APN related configuration. If the apn does not exist, it is automatically created and
+  the default parameters are set.
+  @param[in] apn_id APN ID, range:1-16
+  @param[out] p_info APN configuration
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_get_apn_config(int apn_id, ql_data_call_apn_config_t *p_info)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_SERVICE_NOT_READY;
+    }
+
+    if(p_info == NULL || p_info == NULL) {
+        return QL_ERR_INVALID_ARG;
+    }
+
+    int i = 0;
+    while(i < QL_NET_MAX_DATA_CALL_NUM) {
+        if(data_call_info[i].call_param_info.apn_param
+            && data_call_info[i].call_param_info.apn_param->apn_id == apn_id) {
+            break;
+        }
+        i++;
+    }
+
+    if(i == QL_NET_MAX_DATA_CALL_NUM) { // No found this apn_id.
+        LOGE("Unknown apn_id : %d", apn_id);
+        return QL_ERR_UNKNOWN;
+    } else {
+        memcpy(p_info, &(data_call_info[i].call_param_info.apn_param->apn_info), sizeof(ql_data_call_apn_config_t));
+    }
+
+    return QL_ERR_OK;
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Set APN related configuration,APN ID:1
+  @param[in] p_info APN configuration
+  @return
+  QL_ERR_OK - successful
+  QL_ERR_NOT_INIT - uninitialized
+  QL_ERR_SERVICE_NOT_READY - service is not ready
+  QL_ERR_INVALID_ARG - Invalid arguments
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_set_attach_apn_config(ql_data_call_apn_config_t *p_info)
+{
+    return ql_data_call_set_apn_config(1, p_info);
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief  Registration server error callback. Currently, only if the server exits abnormally,
+  the callback function will be executed, and the error code is QL_ERR_ABORTED;
+  @param[in] cb  Callback function
+  @return
+  QL_ERR_OK - successful
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_set_service_error_cb(ql_data_call_service_error_cb_f cb)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_UNKNOWN;
+    } else {
+        if(mbtk_ril_server_state_change_reg(ql_info_handle, ril_server_state_cb))
+        {
+            return QL_ERR_UNKNOWN;
+        }
+
+        data_call_service_error_cb = cb;
+        return QL_ERR_OK;
+    }
+}
+
+/*-----------------------------------------------------------------------------------------------*/
+/**
+  @brief Deinitialize the data call service
+  @return
+  QL_ERR_OK - successful
+  Other - error code defined by ql_type.h
+  */
+/*-----------------------------------------------------------------------------------------------*/
+int ql_data_call_deinit(void)
+{
+    if(ql_info_handle == NULL)
+    {
+        return QL_ERR_UNKNOWN;
+    } else {
+        if(mbtk_info_handle_free(&ql_info_handle))
+        {
+            return QL_ERR_UNKNOWN;
+        }
+
+        return QL_ERR_OK;
+    }
+}