diff options
author | Srinivas Dasari <dasaris@codeaurora.org> | 2018-01-03 23:21:02 +0530 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2018-01-23 06:49:32 -0800 |
commit | 486a43078fc42efab6bb28a195286f611fc3c72b (patch) | |
tree | 0781cbc253ef7c1100e1966a087147084ce6c12c /qcwcn/wifi_hal/radio_mode.cpp | |
parent | c6ddbe535daff4246aaaecd69f315379d9afd5c3 (diff) | |
download | wlan-486a43078fc42efab6bb28a195286f611fc3c72b.tar.gz |
Wifi-HAL: Provision to get the Wi-Fi interface's MAC mode
This commit introduces a call back to get the interface and
hardware MAC mode information from the driver. This event
is notified from the driver on any connection / disconnection
of a specific interface.
This shall depict the mode (SCC / MCC / DBS) of the MAC
hardware at any given point of time.
Bug: 68349158
Test: Compiles
(cherry-picked from 0833d0fa4eac75ef172b09b51925ad0dafbfc8e7)
Change-Id: Ic9ac81315a9dd50053e927892eb5cf43b999b0d3
Diffstat (limited to 'qcwcn/wifi_hal/radio_mode.cpp')
-rw-r--r-- | qcwcn/wifi_hal/radio_mode.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/qcwcn/wifi_hal/radio_mode.cpp b/qcwcn/wifi_hal/radio_mode.cpp new file mode 100644 index 0000000..96a2176 --- /dev/null +++ b/qcwcn/wifi_hal/radio_mode.cpp @@ -0,0 +1,255 @@ +/* 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. + */ + +#include "sync.h" + +#include <utils/Log.h> + +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" +#include "radio_mode.h" +#include "vendor_definitions.h" +#include <netlink/genl/genl.h> +#include <string.h> +#include <net/if.h> + +/* Used to handle radio mode command events from driver/firmware.*/ +void RADIOModeCommand::setCallbackHandler(wifi_radio_mode_change_handler handler) +{ + mHandler = handler; +} + +void RADIOModeCommand::setReqId(wifi_request_id id) +{ + mreqId = id; +} + +RADIOModeCommand::RADIOModeCommand(wifi_handle handle, int id, + u32 vendor_id, u32 subcmd) + : WifiVendorCommand(handle, id, vendor_id, subcmd) +{ + memset(&mHandler, 0, sizeof(mHandler)); + if (registerVendorHandler(vendor_id, subcmd)) { + /* Error case should not happen print log */ + ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u", + __FUNCTION__, vendor_id, subcmd); + } +} + +RADIOModeCommand::~RADIOModeCommand() +{ + unregisterVendorHandler(mVendor_id, mSubcmd); +} + + +RADIOModeCommand* RADIOModeCommand::instance(wifi_handle handle, + wifi_request_id id) +{ + RADIOModeCommand* mRADIOModeCommandInstance; + + if (handle == NULL) { + ALOGE("Interface Handle is invalid"); + return NULL; + } + hal_info *info = getHalInfo(handle); + if (!info) { + ALOGE("hal_info is invalid"); + return NULL; + } + mRADIOModeCommandInstance = new RADIOModeCommand(handle, id, + OUI_QCA, + QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_MODE); + return mRADIOModeCommandInstance; +} + +/* This function will be the main handler for incoming event. + * Call the appropriate callback handler after parsing the vendor data. + */ +int RADIOModeCommand::handleEvent(WifiEvent &event) +{ + wifi_error ret = WIFI_SUCCESS; + int num_of_mac = 0; + wifi_mac_info mode_info; + + WifiVendorCommand::handleEvent(event); + + /* Parse the vendordata and get the attribute */ + switch(mSubcmd) + { + case QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_MODE: + { + struct nlattr *mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_MAX + 1]; + struct nlattr *modeInfo; + int rem; + + nla_parse(mtb_vendor, QCA_WLAN_VENDOR_ATTR_MAC_MAX, + (struct nlattr *)mVendorData, + mDataLen, NULL); + + if (mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]) + { + for (modeInfo = (struct nlattr *) nla_data(mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]), + rem = nla_len(mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]); + nla_ok(modeInfo, rem);modeInfo = nla_next(modeInfo, &(rem))) { + + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX+ 1]; + nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX, + (struct nlattr *) nla_data(modeInfo), nla_len(modeInfo), NULL); + if (!tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID]) + { + ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID" + " not found", __FUNCTION__); + return WIFI_ERROR_INVALID_ARGS; + } + mode_info.wlan_mac_id = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID]); + ALOGV("mac_id[%d]: %d ", num_of_mac, mode_info.wlan_mac_id); + + if (!tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND]) + { + ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND" + " NOT FOUND", __FUNCTION__); + return WIFI_ERROR_INVALID_ARGS; + } + mode_info.mac_band = (wlan_mac_band) nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND]); + ALOGV("mac_band[%d]: %d ", num_of_mac, mode_info.mac_band); + + if (tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]) + { + int num_of_iface = 0; + struct nlattr *tb_iface; + int rem_info; + + for (tb_iface = (struct nlattr *) nla_data(tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]), + rem_info = nla_len(tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]); + nla_ok(tb_iface, rem_info);tb_iface = nla_next(tb_iface, &(rem_info))) { + + struct nlattr *tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX+ 1]; + wifi_iface_info miface_info; + + nla_parse(tb3, QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX, + (struct nlattr *) nla_data(tb_iface), nla_len(tb_iface), NULL); + + if (!tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_ID]) + { + ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_ID" + " NOT FOUND", __FUNCTION__); + return WIFI_ERROR_INVALID_ARGS; + } + if (if_indextoname(nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_ID]), + miface_info.iface_name) == NULL) + { + ALOGE("%s: Failed to convert %d IFINDEX to IFNAME", __FUNCTION__, + nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_ID])); + } + ALOGV("ifname[%d]: %s ", num_of_iface, miface_info.iface_name); + + if (!tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ]) + { + ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ" + " NOT FOUND", __FUNCTION__); + return WIFI_ERROR_INVALID_ARGS; + } + miface_info.channel = nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ]); + ALOGV("channel[%d]: %d ", num_of_iface, miface_info.channel); + + if (!num_of_iface) + mode_info.iface_info = (wifi_iface_info *) + malloc(sizeof(wifi_iface_info)); + else + mode_info.iface_info = (wifi_iface_info *) + realloc(mode_info.iface_info, (num_of_iface + 1) * sizeof(wifi_iface_info)); + + memcpy(&mode_info.iface_info[num_of_iface], &miface_info, sizeof(wifi_iface_info)); + num_of_iface++; + mode_info.num_iface = num_of_iface; + } + } + if (!num_of_mac) + mwifi_iface_mac_info = (wifi_mac_info *) + malloc(sizeof(wifi_mac_info)); + else + mwifi_iface_mac_info = (wifi_mac_info *) + realloc(mwifi_iface_mac_info, (num_of_mac + 1) * (sizeof(wifi_mac_info))); + + memcpy(&mwifi_iface_mac_info[num_of_mac], &mode_info, sizeof(wifi_mac_info)); + num_of_mac++; + } + } + + if (mHandler.on_radio_mode_change && num_of_mac) { + (*mHandler.on_radio_mode_change)(mreqId, num_of_mac, mwifi_iface_mac_info); + free(mwifi_iface_mac_info); + mwifi_iface_mac_info = NULL; + } + else { + ALOGE("No Callback registered: on radio mode change"); + free(mwifi_iface_mac_info); + mwifi_iface_mac_info = NULL; + } + } + break; + + default: + /* Error case should not happen print log */ + ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd); + } + + return ret; +} + +wifi_error wifi_set_radio_mode_change_handler(wifi_request_id id, + wifi_interface_handle iface, + wifi_radio_mode_change_handler eh) +{ + wifi_error ret; + WifiVendorCommand *vCommand = NULL; + wifi_handle wifiHandle = getWifiHandle(iface); + RADIOModeCommand *radiomodeCommand; + + ret = initialize_vendor_cmd(iface, id, + QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_MODE, + &vCommand); + if (ret != WIFI_SUCCESS) { + ALOGE("%s: Initialization failed", __FUNCTION__); + return ret; + } + + radiomodeCommand = RADIOModeCommand::instance(wifiHandle, id); + if (radiomodeCommand == NULL) { + ALOGE("%s: Error RadioModeCommand NULL", __FUNCTION__); + ret = WIFI_ERROR_OUT_OF_MEMORY; + goto cleanup; + } + radiomodeCommand->setCallbackHandler(eh); + radiomodeCommand->setReqId(id); + +cleanup: + delete vCommand; + return mapKernelErrortoWifiHalError(ret); +} |