aboutsummaryrefslogtreecommitdiff
path: root/location/loc_net_iface/le/LocNetIface.cpp
diff options
context:
space:
mode:
authorRashed Abdel-Tawab <rashed@linux.com>2017-09-19 20:58:32 -0400
committerDavide Garberi <dade.garberi@gmail.com>2017-12-12 23:06:22 +0100
commitb126d0ecb88282b7eff99a61a331caf683257dc3 (patch)
tree05e6e07433b5064454072c10be6f8d2125839ac8 /location/loc_net_iface/le/LocNetIface.cpp
parent20846acdd9f79b031d21d0f074df10bdfbc743e1 (diff)
msm8996-common: Add location from LA.UM.6.5.r1-02500-8x96.0
Signed-off-by: Davide Garberi <dade.garberi@gmail.com>
Diffstat (limited to 'location/loc_net_iface/le/LocNetIface.cpp')
-rw-r--r--location/loc_net_iface/le/LocNetIface.cpp956
1 files changed, 956 insertions, 0 deletions
diff --git a/location/loc_net_iface/le/LocNetIface.cpp b/location/loc_net_iface/le/LocNetIface.cpp
new file mode 100644
index 0000000..fb5febe
--- /dev/null
+++ b/location/loc_net_iface/le/LocNetIface.cpp
@@ -0,0 +1,956 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation, nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define LOG_TAG "LocSvc_LocNetIfaceLE"
+
+#include "LocNetIface.h"
+#include <QCMAP_Client.h>
+#include "qualcomm_mobile_access_point_msgr_v01.h"
+#include <platform_lib_log_util.h>
+#include "DataItemConcreteTypes.h"
+#include <loc_cfg.h>
+#include <platform_lib_macros.h>
+#include <unistd.h>
+
+
+/* LocNetIface singleton instance
+ * Used for QCMAP registration */
+LocNetIface* LocNetIface::sLocNetIfaceInstance = NULL;
+
+
+void LocNetIface::subscribe (
+ const std::list<DataItemId>& itemListToSubscribe) {
+
+ ENTRY_LOG();
+
+ /* Add items to subscribed list */
+ bool anyUpdatesToSubscriptionList =
+ updateSubscribedItemList(itemListToSubscribe, true);
+
+ /* If either of network info items is in subscription list,
+ * subscribe with QCMAP */
+ if (anyUpdatesToSubscriptionList) {
+ if (isItemSubscribed(NETWORKINFO_DATA_ITEM_ID)) {
+ subscribeWithQcmap();
+ notifyCurrentNetworkInfo();
+ }
+ if (isItemSubscribed(WIFIHARDWARESTATE_DATA_ITEM_ID)) {
+ subscribeWithQcmap();
+ notifyCurrentWifiHardwareState();
+ }
+ }
+
+ EXIT_LOG_WITH_ERROR("%d", 0);
+}
+
+void LocNetIface::unsubscribe (
+ const std::list<DataItemId>& itemListToUnsubscribe) {
+
+ ENTRY_LOG();
+
+ /* Remove items from subscribed list */
+ bool anyUpdatesToSubscriptionList =
+ updateSubscribedItemList(itemListToUnsubscribe, false);
+
+ /* If neither of below two items left in subscription, we can unsubscribe
+ * from QCMAP */
+ if (anyUpdatesToSubscriptionList &&
+ !isItemSubscribed(NETWORKINFO_DATA_ITEM_ID) &&
+ !isItemSubscribed(WIFIHARDWARESTATE_DATA_ITEM_ID)) {
+
+ unsubscribeWithQcmap();
+ }
+}
+
+void LocNetIface::unsubscribeAll () {
+
+ ENTRY_LOG();
+
+ /* Check about network items */
+ if (isItemSubscribed(NETWORKINFO_DATA_ITEM_ID) ||
+ isItemSubscribed(WIFIHARDWARESTATE_DATA_ITEM_ID)) {
+
+ unsubscribeWithQcmap();
+ }
+
+ /* Clear subscription list */
+ mSubscribedItemList.clear();
+}
+
+void LocNetIface::requestData (
+ const std::list<DataItemId>& itemListToRequestData) {
+
+ ENTRY_LOG();
+
+ /* NO-OP for LE platform
+ * We don't support any data item to fetch data for */
+}
+
+void LocNetIface::subscribeWithQcmap () {
+
+ ENTRY_LOG();
+
+ qmi_error_type_v01 qcmapErr = QMI_ERR_NONE_V01;
+
+ /* We handle qcmap subscription from an exclusive instance */
+ if (LocNetIface::sLocNetIfaceInstance != NULL) {
+
+ LOC_LOGI("QCMAP registration already done !");
+ return;
+ }
+
+ /* First time registration */
+ if (LocNetIface::sLocNetIfaceInstance == NULL) {
+ LocNetIface::sLocNetIfaceInstance = this;
+ }
+
+ /* Are we already subscribed */
+ if (mQcmapClientPtr != NULL) {
+ LOC_LOGW("Already subscribed !");
+ return;
+ }
+
+ /* Create a QCMAP Client instance */
+ mQcmapClientPtr = new QCMAP_Client(qcmapClientCallback);
+ if (mQcmapClientPtr == NULL) {
+ LOC_LOGE("Failed to allocate QCMAP instance !");
+ return;
+ }
+ LOC_LOGD("Created QCMAP_Client instance %p", mQcmapClientPtr);
+
+ /* Need to enable MobileAP to get station mode status indications */
+ bool ret = mQcmapClientPtr->EnableMobileAP(&qcmapErr);
+ if (ret == false || qcmapErr != 0) {
+ LOC_LOGE("Failed to enable mobileap, qcmapErr %d", qcmapErr);
+ }
+ /* Invoke WLAN status registration
+ * WWAN is by default registered */
+ ret = mQcmapClientPtr->RegisterForWLANStatusIND(&qcmapErr, true);
+ if (ret == false || qcmapErr != 0) {
+ LOC_LOGE("RegisterForWLANStatusIND failed, qcmapErr %d", qcmapErr);
+ }
+}
+
+void LocNetIface::unsubscribeWithQcmap () {
+
+ ENTRY_LOG();
+
+ // Simply deleting the qcmap client instance is enough
+ if (mQcmapClientPtr == NULL) {
+ LOC_LOGE("No QCMAP instance to unsubscribe from");
+ return;
+ }
+
+ delete mQcmapClientPtr;
+ mQcmapClientPtr = NULL;
+}
+
+void LocNetIface::qcmapClientCallback (
+ qmi_client_type user_handle, /**< QMI user handle. */
+ unsigned int msg_id, /**< Indicator message ID. */
+ void *ind_buf, /**< Raw indication data. */
+ unsigned int ind_buf_len, /**< Raw data length. */
+ void *ind_cb_data /**< User callback handle. */ ) {
+
+ ENTRY_LOG();
+
+ qmi_client_error_type qmi_error;
+
+ // Check the message type
+ // msg_id = QMI_QCMAP_MSGR_WLAN_STATUS_IND_V01
+ // ind_buf = qcmap_msgr_wlan_status_ind_msg_v01
+ switch (msg_id) {
+
+ case QMI_QCMAP_MSGR_WLAN_STATUS_IND_V01: {
+ LOC_LOGD("Received QMI_QCMAP_MSGR_WLAN_STATUS_IND_V01");
+
+ qcmap_msgr_wlan_status_ind_msg_v01 wlanStatusIndData;
+
+ /* Parse the indication */
+ qmi_error = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION,
+ msg_id, ind_buf, ind_buf_len, &wlanStatusIndData,
+ sizeof(qcmap_msgr_wlan_status_ind_msg_v01));
+
+ if (qmi_error != QMI_NO_ERR) {
+ LOC_LOGE("qmi_client_message_decode error %d", qmi_error);
+ return;
+ }
+
+ LocNetIface::sLocNetIfaceInstance->handleQcmapCallback(wlanStatusIndData);
+ break;
+ }
+
+ case QMI_QCMAP_MSGR_STATION_MODE_STATUS_IND_V01: {
+ LOC_LOGD("Received QMI_QCMAP_MSGR_STATION_MODE_STATUS_IND_V01");
+
+ qcmap_msgr_station_mode_status_ind_msg_v01 stationModeIndData;
+
+ /* Parse the indication */
+ qmi_error = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION,
+ msg_id, ind_buf, ind_buf_len, &stationModeIndData,
+ sizeof(qcmap_msgr_station_mode_status_ind_msg_v01));
+
+ if (qmi_error != QMI_NO_ERR) {
+ LOC_LOGE("qmi_client_message_decode error %d", qmi_error);
+ return;
+ }
+
+ LocNetIface::sLocNetIfaceInstance->handleQcmapCallback(stationModeIndData);
+ break;
+ }
+
+ case QMI_QCMAP_MSGR_WWAN_STATUS_IND_V01: {
+ LOC_LOGD("Received QMI_QCMAP_MSGR_WWAN_STATUS_IND_V01");
+
+ qcmap_msgr_wwan_status_ind_msg_v01 wwanStatusIndData;
+
+ /* Parse the indication */
+ qmi_error = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION,
+ msg_id, ind_buf, ind_buf_len, &wwanStatusIndData,
+ sizeof(qcmap_msgr_wwan_status_ind_msg_v01));
+
+ if (qmi_error != QMI_NO_ERR) {
+ LOC_LOGE("qmi_client_message_decode error %d", qmi_error);
+ return;
+ }
+
+ LocNetIface::sLocNetIfaceInstance->handleQcmapCallback(wwanStatusIndData);
+ break;
+ }
+
+ case QMI_QCMAP_MSGR_BRING_UP_WWAN_IND_V01: {
+ LOC_LOGD("Received QMI_QCMAP_MSGR_BRING_UP_WWAN_IND_V01");
+
+ qcmap_msgr_bring_up_wwan_ind_msg_v01 bringUpWwanIndData;
+
+ /* Parse the indication */
+ qmi_error = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION,
+ msg_id, ind_buf, ind_buf_len, &bringUpWwanIndData,
+ sizeof(qcmap_msgr_bring_up_wwan_ind_msg_v01));
+
+ if (qmi_error != QMI_NO_ERR) {
+ LOC_LOGE("qmi_client_message_decode error %d", qmi_error);
+ return;
+ }
+
+ LocNetIface::sLocNetIfaceInstance->handleQcmapCallback(bringUpWwanIndData);
+ break;
+ }
+
+ case QMI_QCMAP_MSGR_TEAR_DOWN_WWAN_IND_V01: {
+ LOC_LOGD("Received QMI_QCMAP_MSGR_TEAR_DOWN_WWAN_IND_V01");
+
+ qcmap_msgr_tear_down_wwan_ind_msg_v01 teardownWwanIndData;
+
+ /* Parse the indication */
+ qmi_error = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION,
+ msg_id, ind_buf, ind_buf_len, &teardownWwanIndData,
+ sizeof(qcmap_msgr_tear_down_wwan_ind_msg_v01));
+
+ if (qmi_error != QMI_NO_ERR) {
+ LOC_LOGE("qmi_client_message_decode error %d", qmi_error);
+ return;
+ }
+
+ LocNetIface::sLocNetIfaceInstance->handleQcmapCallback(teardownWwanIndData);
+ break;
+ }
+
+ default:
+ LOC_LOGE("Ignoring QCMAP indication: %d", msg_id);
+ }
+}
+
+void LocNetIface::handleQcmapCallback (
+ qcmap_msgr_wlan_status_ind_msg_v01 &wlanStatusIndData) {
+
+ ENTRY_LOG();
+
+ LOC_LOGD("WLAN Status (enabled=1, disabled=2): %d",
+ wlanStatusIndData.wlan_status);
+
+ LOC_LOGD("WLAN Mode (AP=1, ... STA=6): %d",
+ wlanStatusIndData.wlan_mode);
+
+ /* Notify observers */
+ if (wlanStatusIndData.wlan_status == QCMAP_MSGR_WLAN_ENABLED_V01) {
+ notifyObserverForWlanStatus(true);
+ } else if (wlanStatusIndData.wlan_status == QCMAP_MSGR_WLAN_DISABLED_V01) {
+ notifyObserverForWlanStatus(false);
+ } else {
+ LOC_LOGE("Invalid wlan status %d", wlanStatusIndData.wlan_status);
+ }
+}
+void LocNetIface::handleQcmapCallback (
+ qcmap_msgr_station_mode_status_ind_msg_v01 &stationModeIndData){
+
+ ENTRY_LOG();
+
+ LOC_LOGI("station mode status: %d", stationModeIndData.station_mode_status);
+
+ /* Notify observers */
+ if (stationModeIndData.station_mode_status ==
+ QCMAP_MSGR_STATION_MODE_CONNECTED_V01) {
+ notifyObserverForNetworkInfo(true, LOC_NET_CONN_TYPE_WLAN);
+ } else if (stationModeIndData.station_mode_status ==
+ QCMAP_MSGR_STATION_MODE_DISCONNECTED_V01) {
+ notifyObserverForNetworkInfo(false, LOC_NET_CONN_TYPE_WLAN);
+ } else {
+ LOC_LOGE("Unhandled station mode status %d",
+ stationModeIndData.station_mode_status);
+ }
+}
+void LocNetIface::handleQcmapCallback (
+ qcmap_msgr_wwan_status_ind_msg_v01 &wwanStatusIndData) {
+
+ ENTRY_LOG();
+
+ LOC_LOGD("WWAN Status (Connected_v4=3, Disconnected_v4=6): %d",
+ wwanStatusIndData.wwan_status);
+
+ /* Notify observers */
+ if (wwanStatusIndData.wwan_status ==
+ QCMAP_MSGR_WWAN_STATUS_CONNECTED_V01) {
+ notifyObserverForNetworkInfo(true, LOC_NET_CONN_TYPE_WWAN_INTERNET);
+ } else if (wwanStatusIndData.wwan_status ==
+ QCMAP_MSGR_WWAN_STATUS_DISCONNECTED_V01) {
+ notifyObserverForNetworkInfo(false, LOC_NET_CONN_TYPE_WWAN_INTERNET);
+ } else {
+ LOC_LOGW("Unsupported wwan status %d",
+ wwanStatusIndData.wwan_status);
+ }
+}
+void LocNetIface::handleQcmapCallback (
+ qcmap_msgr_bring_up_wwan_ind_msg_v01 &bringUpWwanIndData) {
+
+ ENTRY_LOG();
+
+ LOC_LOGD("WWAN Bring up status (Connected=3, Disconnected=6): %d",
+ bringUpWwanIndData.conn_status);
+
+ /* Notify observers */
+ if (bringUpWwanIndData.conn_status ==
+ QCMAP_MSGR_WWAN_STATUS_CONNECTED_V01) {
+
+ notifyObserverForNetworkInfo(true, LOC_NET_CONN_TYPE_WWAN_INTERNET);
+
+ if (mIsConnectBackhaulPending &&
+ mWwanCallStatusCb != NULL){
+ LOC_LOGV("LOC_NET_WWAN_CALL_EVT_OPEN_SUCCESS");
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_OPEN_SUCCESS,
+ getApnNameFromConfig(), getIpTypeFromConfig());
+ }
+ mIsConnectBackhaulPending = false;
+
+ } else if (bringUpWwanIndData.conn_status ==
+ QCMAP_MSGR_WWAN_STATUS_CONNECTING_FAIL_V01) {
+
+ if (mIsConnectBackhaulPending &&
+ mWwanCallStatusCb != NULL){
+ LOC_LOGV("LOC_NET_WWAN_CALL_EVT_OPEN_FAILED");
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_OPEN_FAILED, NULL,
+ LOC_NET_CONN_IP_TYPE_INVALID);
+ }
+ mIsConnectBackhaulPending = false;
+
+ } else {
+ LOC_LOGW("Unsupported wwan status %d",
+ bringUpWwanIndData.conn_status);
+ }
+}
+
+void LocNetIface::handleQcmapCallback(
+ qcmap_msgr_tear_down_wwan_ind_msg_v01 &teardownWwanIndData) {
+
+ ENTRY_LOG();
+
+ LOC_LOGD("WWAN teardown status (Connected=3, Disconnected=6): %d",
+ teardownWwanIndData.conn_status);
+
+ /* Notify observers */
+ if (teardownWwanIndData.conn_status ==
+ QCMAP_MSGR_WWAN_STATUS_DISCONNECTED_V01) {
+
+ notifyObserverForNetworkInfo(false, LOC_NET_CONN_TYPE_WWAN_INTERNET);
+
+ if (mIsDisconnectBackhaulPending &&
+ mWwanCallStatusCb != NULL) {
+ LOC_LOGV("LOC_NET_WWAN_CALL_EVT_CLOSE_SUCCESS");
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_CLOSE_SUCCESS,
+ getApnNameFromConfig(), getIpTypeFromConfig());
+ }
+ mIsDisconnectBackhaulPending = false;
+
+ } else if (teardownWwanIndData.conn_status ==
+ QCMAP_MSGR_WWAN_STATUS_DISCONNECTING_FAIL_V01) {
+
+ if (mIsDisconnectBackhaulPending &&
+ mWwanCallStatusCb != NULL){
+ LOC_LOGV("LOC_NET_WWAN_CALL_EVT_CLOSE_FAILED");
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_CLOSE_FAILED, NULL,
+ LOC_NET_CONN_IP_TYPE_INVALID);
+ }
+ mIsDisconnectBackhaulPending = false;
+
+ } else {
+ LOC_LOGW("Unsupported wwan status %d",
+ teardownWwanIndData.conn_status);
+ }
+}
+
+void LocNetIface::notifyCurrentNetworkInfo () {
+
+ ENTRY_LOG();
+
+ /* Validate QCMAP Client instance */
+ if (mQcmapClientPtr == NULL) {
+ LOC_LOGE("No QCMAP instance !");
+ return;
+ }
+
+ /* Fetch station mode status and notify observers */
+ if (isWlanConnected()) {
+ notifyObserverForNetworkInfo(true, LOC_NET_CONN_TYPE_WLAN);
+ } else {
+ notifyObserverForNetworkInfo(false, LOC_NET_CONN_TYPE_WLAN);
+ }
+
+ /* Fetch WWAN status and notify observers */
+ if (isWwanConnected()) {
+ notifyObserverForNetworkInfo(true, LOC_NET_CONN_TYPE_WWAN_INTERNET);
+ } else {
+ notifyObserverForNetworkInfo(false, LOC_NET_CONN_TYPE_WWAN_INTERNET);
+ }
+}
+
+void LocNetIface::notifyCurrentWifiHardwareState () {
+
+ ENTRY_LOG();
+
+ /* Validate QCMAP Client instance */
+ if (mQcmapClientPtr == NULL) {
+ LOC_LOGE("No QCMAP instance !");
+ return;
+ }
+
+ /* Fetch WLAN status */
+ qcmap_msgr_wlan_mode_enum_v01 wlan_mode =
+ QCMAP_MSGR_WLAN_MODE_ENUM_MIN_ENUM_VAL_V01;
+ qmi_error_type_v01 qmi_err_num = QMI_ERROR_TYPE_MIN_ENUM_VAL_V01;
+
+ if (!mQcmapClientPtr->GetWLANStatus(&wlan_mode, &qmi_err_num)) {
+ LOC_LOGE("Failed to fetch wlan status, err %d", qmi_err_num);
+ return;
+ }
+
+ if (wlan_mode == QCMAP_MSGR_WLAN_MODE_ENUM_MIN_ENUM_VAL_V01) {
+ notifyObserverForWlanStatus(false);
+ } else if (wlan_mode == QCMAP_MSGR_WLAN_MODE_STA_ONLY_V01 ||
+ wlan_mode == QCMAP_MSGR_WLAN_MODE_AP_STA_V01 ||
+ wlan_mode == QCMAP_MSGR_WLAN_MODE_AP_AP_STA_V01 ||
+ wlan_mode == QCMAP_MSGR_WLAN_MODE_AP_STA_BRIDGE_V01 ||
+ wlan_mode == QCMAP_MSGR_WLAN_MODE_AP_AP_STA_BRIDGE_V01 ||
+ wlan_mode == QCMAP_MSGR_WLAN_MODE_STA_ONLY_BRIDGE_V01) {
+ LOC_LOGD("notifying abt WLAN mode: %d", wlan_mode);
+ notifyObserverForWlanStatus(true);
+ }
+}
+
+void LocNetIface::notifyObserverForWlanStatus (bool isWlanEnabled) {
+
+ ENTRY_LOG();
+
+ /* Validate subscription object */
+ if (LocNetIfaceBase::sNotifyCb == NULL){
+ LOC_LOGE("Notify callback NULL !");
+ return;
+ }
+
+ /* Create a wifi hardware status item */
+ WifiHardwareStateDataItem wifiStateDataItem;
+ IDataItem *dataItem = NULL;
+
+ wifiStateDataItem.mEnabled = isWlanEnabled;
+ dataItem = &wifiStateDataItem;
+
+ // Create a list and push data item, since that's what observer expects
+ std::list<IDataItem *> dataItemList;
+ dataItemList.push_back(dataItem);
+
+ /* Notify back to client */
+ LocNetIfaceBase::sNotifyCb(
+ LocNetIfaceBase::sNotifyCbUserDataPtr, dataItemList);
+}
+
+void LocNetIface::notifyObserverForNetworkInfo (
+ boolean isConnected, LocNetConnType connType){
+
+ ENTRY_LOG();
+
+ // Check if observer is registered
+ if (LocNetIfaceBase::sNotifyCb == NULL) {
+ LOC_LOGE("Notify callback NULL !");
+ return;
+ }
+
+ // Create a network data item
+ NetworkInfoDataItem networkInfoDataItem;
+ IDataItem *dataItem = NULL;
+
+ networkInfoDataItem.mType = (int32)connType;
+ networkInfoDataItem.mConnected = isConnected;
+
+ dataItem = &networkInfoDataItem;
+
+ // Create a list and push data item, since that's what observer expects
+ std::list<IDataItem *> dataItemList;
+ dataItemList.push_back(dataItem);
+
+ /* Notify back to client */
+ LocNetIfaceBase::sNotifyCb(
+ LocNetIfaceBase::sNotifyCbUserDataPtr, dataItemList);
+}
+
+bool LocNetIface::setupWwanCall () {
+
+ ENTRY_LOG();
+
+ /* Validate call type requested */
+ if (mLocNetConnType != LOC_NET_CONN_TYPE_WWAN_SUPL) {
+ LOC_LOGE("Unsupported call type configured: %d", mLocNetConnType);
+ return false;
+ }
+
+ /* Check for ongoing start/stop attempts */
+ if (mIsDsiStartCallPending) {
+ LOC_LOGW("Already start pending, returning as no-op");
+ return true;
+ }
+ if (mIsDsiStopCallPending) {
+ LOC_LOGE("Stop attempt pending, can't start now !");
+ /* When stop completes and DS callback is received, we will
+ * notify the client. So no need to notify now. */
+ return false;
+ }
+ if (mIsDsiCallUp) {
+ LOC_LOGW("Already ongoing data call");
+ if (mWwanCallStatusCb != NULL) {
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_OPEN_SUCCESS,
+ getApnNameFromConfig(), getIpTypeFromConfig());
+ }
+ return true;
+ }
+
+ /* Initialize DSI library */
+ int ret = -1;
+ if (!mIsDsiInitDone) {
+
+ if ((ret = dsi_init(DSI_MODE_GENERAL)) == DSI_SUCCESS) {
+ LOC_LOGI("dsi_init success !");
+ } else if (ret == DSI_EINITED) {
+ LOC_LOGI("dsi_init already done !");
+ } else {
+ LOC_LOGE("dsi_init failed, err %d", ret);
+ }
+ mIsDsiInitDone = true;
+
+ /* Sleep 100 ms for dsi_init() to complete */
+ LOC_LOGV("Sleeping for 100 ms");
+ usleep(100 * 1000);
+ }
+
+ /* Get DSI service handle */
+ if (mDsiHandle == NULL) {
+ mDsiHandle = dsi_get_data_srvc_hndl(
+ LocNetIface::dsiNetEventCallback, this);
+ if (mDsiHandle == NULL) {
+ LOC_LOGE("NULL DSI Handle");
+ return false;
+ }
+ }
+ LOC_LOGD("DSI Handle for call %p", mDsiHandle);
+
+ /* Set call parameters */
+ dsi_call_param_value_t callParams;
+
+ /* No Radio tech preference */
+ callParams.buf_val = NULL;
+ callParams.num_val = DSI_RADIO_TECH_UNKNOWN;
+ LOC_LOGD("DSI_CALL_INFO_TECH_PREF = DSI_RADIO_TECH_UNKNOWN");
+ dsi_set_data_call_param(mDsiHandle, DSI_CALL_INFO_TECH_PREF, &callParams);
+
+ /* APN from gps.conf */
+ char* apnName = getApnNameFromConfig();
+ int apnNameLen = strnlen(apnName, APN_NAME_MAX_LEN);
+ if (apnName != NULL && apnNameLen > 0) {
+ callParams.buf_val = apnName;
+ callParams.num_val = apnNameLen;
+ LOC_LOGD("DSI_CALL_INFO_APN_NAME = %s", apnName);
+ dsi_set_data_call_param(mDsiHandle, DSI_CALL_INFO_APN_NAME, &callParams);
+ } else{
+ LOC_LOGE("Failed to fetch APN for data call setup");
+ return false;
+ }
+
+ /* IP type from gps.conf */
+ LocNetConnIpType ipType = getIpTypeFromConfig();
+ callParams.buf_val = NULL;
+ if (ipType == LOC_NET_CONN_IP_TYPE_V4) {
+ callParams.num_val = DSI_IP_VERSION_4;
+ } else if (ipType == LOC_NET_CONN_IP_TYPE_V6) {
+ callParams.num_val = DSI_IP_VERSION_6;
+ } else if (ipType == LOC_NET_CONN_IP_TYPE_V4V6) {
+ callParams.num_val = DSI_IP_VERSION_4_6;
+ } else {
+ LOC_LOGE("No IP Type in gps.conf, using default v4");
+ callParams.num_val = DSI_IP_VERSION_4;
+ }
+ dsi_set_data_call_param(
+ mDsiHandle, DSI_CALL_INFO_IP_VERSION, &callParams);
+
+ /* Send the call setup request */
+ ret = dsi_start_data_call(mDsiHandle);
+ if (ret != DSI_SUCCESS) {
+
+ LOC_LOGE("DSI_START_DATA_CALL FAILED, err %d", ret);
+ return false;
+ }
+
+ mIsDsiStartCallPending = true;
+ LOC_LOGI("Data call START request sent successfully to DSI");
+ return true;
+}
+
+bool LocNetIface::stopWwanCall () {
+
+ ENTRY_LOG();
+
+ /* Check for ongoing start/stop attempts */
+ if (mIsDsiStopCallPending) {
+ LOC_LOGW("Already stop pending, no-op");
+ return true;
+ }
+ if (mIsDsiStartCallPending) {
+ LOC_LOGE("Start attempt pending, can't stop now !");
+ /* When start completes and DS callback is received, we will
+ * notify the client. So no need to notify now. */
+ return false;
+ }
+ if (!mIsDsiCallUp) {
+ LOC_LOGE("No ongoing data call to stop");
+ if (mWwanCallStatusCb != NULL) {
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_CLOSE_SUCCESS,
+ getApnNameFromConfig(), getIpTypeFromConfig());
+ }
+ return true;
+ }
+
+ /* Stop the call */
+ LOC_LOGD("Stopping data call with handle %p", mDsiHandle);
+
+ int ret = dsi_stop_data_call(mDsiHandle);
+ if (ret != DSI_SUCCESS) {
+
+ LOC_LOGE("dsi_stop_data_call() returned err %d", ret);
+ return false;
+ }
+
+ mIsDsiStopCallPending = true;
+ LOC_LOGI("Data call STOP request sent to DS");
+ return true;
+}
+
+/* Static callback method */
+void LocNetIface::dsiNetEventCallback (
+ dsi_hndl_t dsiHandle, void* userDataPtr, dsi_net_evt_t event,
+ dsi_evt_payload_t* eventPayloadPtr){
+
+ ENTRY_LOG();
+
+ /* Analyze event payload */
+ LocNetIface* locNetIface = static_cast<LocNetIface*>(userDataPtr);
+ if (locNetIface == NULL){
+ LOC_LOGE("Null user data !");
+ return;
+ }
+
+ if (event == DSI_EVT_NET_IS_CONN){
+ LOC_LOGI("DSI_EVT_NET_IS_CONN");
+ locNetIface->handleDSCallback(dsiHandle, true);
+ } else if (event == DSI_EVT_NET_NO_NET){
+ LOC_LOGI("DSI_EVT_NET_NO_NET");
+ locNetIface->handleDSCallback(dsiHandle, false);
+ } else {
+ LOC_LOGW("Unsupported event %d", event);
+ }
+}
+
+void LocNetIface::handleDSCallback (
+ dsi_hndl_t dsiHandle, bool isNetConnected){
+
+ ENTRY_LOG();
+ LOC_LOGV("dsiHandle %p, isCallUp %d, stopPending %d, startPending %d",
+ dsiHandle, mIsDsiCallUp, mIsDsiStopCallPending,
+ mIsDsiStartCallPending);
+
+ /* Validate handle */
+ if (mDsiHandle != dsiHandle){
+ LOC_LOGE("DS Handle mismatch: %p vs %p", mDsiHandle, dsiHandle);
+ return;
+ }
+
+ /* Process event */
+ if (isNetConnected){
+
+ /* Invoke client callback if registered*/
+ if (mIsDsiStartCallPending &&
+ mWwanCallStatusCb != NULL){
+ LOC_LOGV("LOC_NET_WWAN_CALL_EVT_OPEN_SUCCESS");
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_OPEN_SUCCESS,
+ getApnNameFromConfig(), getIpTypeFromConfig());
+ }
+
+ /* Start call complete */
+ mIsDsiCallUp = true;
+ mIsDsiStartCallPending = false;
+
+ } else {
+
+ /* Invoke client callback if registered */
+ if (mIsDsiStopCallPending &&
+ mWwanCallStatusCb != NULL) {
+ LOC_LOGV("LOC_NET_WWAN_CALL_EVT_CLOSE_SUCCESS");
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_CLOSE_SUCCESS,
+ getApnNameFromConfig(), getIpTypeFromConfig());
+ } else if (mIsDsiStartCallPending &&
+ mWwanCallStatusCb != NULL){
+ LOC_LOGV("LOC_NET_WWAN_CALL_EVT_OPEN_FAILED");
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_OPEN_FAILED, NULL,
+ LOC_NET_CONN_IP_TYPE_INVALID);
+ }
+
+ /* Stop call complete */
+ mIsDsiCallUp = false;
+ mIsDsiStopCallPending = false;
+ }
+}
+
+bool LocNetIface::isWlanConnected() {
+
+ ENTRY_LOG();
+
+ /* Access QCMAP instance only from the static instance */
+ if (this != LocNetIface::sLocNetIfaceInstance &&
+ LocNetIface::sLocNetIfaceInstance != NULL) {
+ return LocNetIface::sLocNetIfaceInstance->isWlanConnected();
+ }
+
+ /* Validate QCMAP Client instance */
+ if (mQcmapClientPtr == NULL) {
+ LOC_LOGE("No QCMAP instance !");
+ return false;
+ }
+
+ /* Fetch station mode status */
+ qcmap_msgr_station_mode_status_enum_v01 status =
+ QCMAP_MSGR_STATION_MODE_STATUS_ENUM_MIN_ENUM_VAL_V01;
+ qmi_error_type_v01 qmi_err_num = QMI_ERROR_TYPE_MIN_ENUM_VAL_V01;
+
+ if (!mQcmapClientPtr->GetStationModeStatus(&status, &qmi_err_num)) {
+ LOC_LOGE("Failed to fetch station mode status, err %d", qmi_err_num);
+ return false;
+ }
+
+ /* Notify observers */
+ if (status == QCMAP_MSGR_STATION_MODE_CONNECTED_V01) {
+ LOC_LOGV("WLAN is connected.");
+ return true;
+ } else if (status == QCMAP_MSGR_STATION_MODE_DISCONNECTED_V01) {
+ LOC_LOGV("WLAN is disconnected.");
+ return false;
+ } else {
+ LOC_LOGE("Unhandled station mode status %d", status);
+ }
+
+ return false;
+}
+
+bool LocNetIface::isWwanConnected() {
+
+ ENTRY_LOG();
+
+ /* Access QCMAP instance only from the static instance */
+ if (this != LocNetIface::sLocNetIfaceInstance &&
+ LocNetIface::sLocNetIfaceInstance != NULL) {
+ return LocNetIface::sLocNetIfaceInstance->isWwanConnected();
+ }
+
+ /* Validate QCMAP Client instance */
+ if (mQcmapClientPtr == NULL) {
+ LOC_LOGE("No QCMAP instance !");
+ return false;
+ }
+
+ /* Fetch backhaul status */
+ qmi_error_type_v01 qmi_err_num = QMI_ERR_NONE_V01;
+ qcmap_msgr_wwan_status_enum_v01 v4_status, v6_status;
+ if (mQcmapClientPtr->GetWWANStatus(
+ &v4_status, &v6_status, &qmi_err_num) == false) {
+ LOC_LOGE("Failed to get wwan status, err 0x%x", qmi_err_num);
+ return false;
+ }
+ if (v4_status == QCMAP_MSGR_WWAN_STATUS_CONNECTED_V01) {
+ LOC_LOGV("WWAN is connected.");
+ return true;
+ } else if (v4_status == QCMAP_MSGR_WWAN_STATUS_DISCONNECTED_V01) {
+ LOC_LOGV("WWAN is disconnected.");
+ return false;
+ } else {
+ LOC_LOGE("Unhandled wwan status %d", v4_status);
+ }
+
+ return false;
+}
+
+bool LocNetIface::connectBackhaul() {
+
+ ENTRY_LOG();
+
+ /* Access QCMAP instance only from the static instance */
+ if (this != LocNetIface::sLocNetIfaceInstance &&
+ LocNetIface::sLocNetIfaceInstance != NULL) {
+ LOC_LOGV("Invoke from static LocNetIface instance..");
+ if (mWwanCallStatusCb != NULL) {
+ LocNetIface::sLocNetIfaceInstance->
+ registerWwanCallStatusCallback(
+ mWwanCallStatusCb, mWwanCbUserDataPtr);
+ }
+ return LocNetIface::sLocNetIfaceInstance->connectBackhaul();
+ }
+
+ /* QCMAP client instance must have been created.
+ * Happens when some client subscribes. */
+ if (mQcmapClientPtr == NULL) {
+ LOC_LOGE("No QCMAP instance");
+ return false;
+ }
+
+ /* Check if backhaul is already connected */
+ qmi_error_type_v01 qmi_err_num = QMI_ERR_NONE_V01;
+ qcmap_msgr_wwan_status_enum_v01 v4_status, v6_status;
+ if (mQcmapClientPtr->GetWWANStatus(
+ &v4_status, &v6_status, &qmi_err_num) == false) {
+ LOC_LOGE("Failed to get wwan status, err 0x%x", qmi_err_num);
+ return false;
+ }
+ if (v4_status == QCMAP_MSGR_WWAN_STATUS_CONNECTING_V01) {
+ LOC_LOGI("Connection attempt already ongoing.");
+ return true;
+ }
+ if (v4_status == QCMAP_MSGR_WWAN_STATUS_CONNECTED_V01) {
+ LOC_LOGV("Backhaul already connected !");
+ if (mWwanCallStatusCb != NULL) {
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_OPEN_SUCCESS,
+ getApnNameFromConfig(), getIpTypeFromConfig());
+ }
+ return true;
+ }
+
+ /* Check if we've already sent the request */
+ if (mConnectBackhaulSent) {
+ LOC_LOGE("Connect request already sent !");
+ return true;
+ }
+
+ /* Send connect request to QCMAP */
+ qmi_err_num = QMI_ERR_NONE_V01;
+ LOC_LOGV("Sending ConnectBackhaul request..");
+ if (mQcmapClientPtr->ConnectBackHaul(
+ QCMAP_MSGR_WWAN_CALL_TYPE_V4_V01, &qmi_err_num) == false) {
+ LOC_LOGE("Connect backhaul failed, err 0x%x", qmi_err_num);
+ return false;
+ }
+
+ /* Set the flag to track */
+ mConnectBackhaulSent = true;
+ mIsConnectBackhaulPending = true;
+ return true;
+}
+
+bool LocNetIface::disconnectBackhaul() {
+
+ ENTRY_LOG();
+
+ /* Access QCMAP instance only from the static instance */
+ if (this != LocNetIface::sLocNetIfaceInstance &&
+ LocNetIface::sLocNetIfaceInstance != NULL) {
+ return LocNetIface::sLocNetIfaceInstance->disconnectBackhaul();
+ }
+
+ /* QCMAP client instance must have been created.
+ * Happens when some client subscribes. */
+ if (mQcmapClientPtr == NULL) {
+ LOC_LOGE("No QCMAP instance");
+ return false;
+ }
+
+ /* Check if we've sent the request.
+ * If we didn't send the connect request, no need to disconnect */
+ if (!mConnectBackhaulSent) {
+ LOC_LOGE("No connect req from us, ignore disconnect req");
+ if (mWwanCallStatusCb != NULL) {
+ mWwanCallStatusCb(
+ mWwanCbUserDataPtr, LOC_NET_WWAN_CALL_EVT_CLOSE_SUCCESS,
+ getApnNameFromConfig(), getIpTypeFromConfig());
+ }
+ return true;
+ }
+
+ /* Send disconnect request to QCMAP */
+ qmi_error_type_v01 qmi_err_num = QMI_ERR_NONE_V01;
+ LOC_LOGV("Sending DisconnectBackhaul..");
+ if (mQcmapClientPtr->DisconnectBackHaul(
+ QCMAP_MSGR_WWAN_CALL_TYPE_V4_V01, &qmi_err_num) == false) {
+ LOC_LOGE("Disconnect backhaul failed, err 0x%x", qmi_err_num);
+ return false;
+ }
+
+ /* Set the flag to track */
+ mConnectBackhaulSent = false;
+ mIsDisconnectBackhaulPending = true;
+ return true;
+}