diff options
Diffstat (limited to 'MediaTek/wifi/rtt.cpp')
| -rw-r--r-- | MediaTek/wifi/rtt.cpp | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/MediaTek/wifi/rtt.cpp b/MediaTek/wifi/rtt.cpp new file mode 100644 index 0000000..62c9c27 --- /dev/null +++ b/MediaTek/wifi/rtt.cpp @@ -0,0 +1,320 @@ +#include <stdint.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/family.h> +#include <netlink/genl/ctrl.h> +#include <linux/rtnetlink.h> +#include <netpacket/packet.h> +#include <linux/filter.h> +#include <linux/errqueue.h> + +#include <linux/pkt_sched.h> +#include <netlink/object-api.h> +#include <netlink/netlink.h> +#include <netlink/socket.h> +#include <netlink-types.h> + +#include "nl80211_copy.h" + +#include "sync.h" + +#define LOG_TAG "WifiHAL" + +#include <utils/Log.h> + +#include "wifi_hal.h" +#include "common.h" +#include "cpp_bindings.h" + +typedef enum { + + RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START, + RTT_SUBCMD_CANCEL_CONFIG, + RTT_SUBCMD_GETCAPABILITY, +} RTT_SUB_COMMAND; + +typedef enum { + RTT_ATTRIBUTE_TARGET_CNT, + RTT_ATTRIBUTE_TARGET_INFO, + RTT_ATTRIBUTE_TARGET_MAC, + RTT_ATTRIBUTE_TARGET_TYPE, + RTT_ATTRIBUTE_TARGET_PEER, + RTT_ATTRIBUTE_TARGET_CHAN, + RTT_ATTRIBUTE_TARGET_MODE, + RTT_ATTRIBUTE_TARGET_INTERVAL, + RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT, + RTT_ATTRIBUTE_TARGET_NUM_PKT, + RTT_ATTRIBUTE_TARGET_NUM_RETRY, + +} GSCAN_ATTRIBUTE; +class GetRttCapabilitiesCommand : public WifiCommand +{ + wifi_rtt_capabilities *mCapabilities; +public: + GetRttCapabilitiesCommand(wifi_interface_handle iface, wifi_rtt_capabilities *capabitlites) + : WifiCommand(iface, 0), mCapabilities(capabitlites) + { + memset(mCapabilities, 0, sizeof(*mCapabilities)); + } + + virtual int create() { + //ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id); + + int ret = mMsg.create(GOOGLE_OUI, RTT_SUBCMD_GETCAPABILITY); + if (ret < 0) { + return ret; + } + + return ret; + } + +protected: + virtual int handleResponse(WifiEvent& reply) { + + //ALOGD("In GetRttCapabilitiesCommand::handleResponse"); + + if (reply.get_cmd() != NL80211_CMD_VENDOR) { + //ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); + return NL_SKIP; + } + + int id = reply.get_vendor_id(); + int subcmd = reply.get_vendor_subcmd(); + + void *data = reply.get_vendor_data(); + int len = reply.get_vendor_data_len(); + + //ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len, + sizeof(*mCapabilities)); + + memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities))); + + return NL_OK; + } +}; + + +class RttCommand : public WifiCommand +{ + unsigned numRttParams; + static const int MAX_RESULTS = 64; + wifi_rtt_result rttResults[MAX_RESULTS]; + wifi_rtt_config *rttParams; + wifi_rtt_event_handler rttHandler; +public: + RttCommand(wifi_interface_handle iface, int id, unsigned num_rtt_config, + wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler) + : WifiCommand(iface, id), numRttParams(num_rtt_config), rttParams(rtt_config), + rttHandler(handler) + { } + + + int createSetupRequest(WifiRequest& request) { + int result = request.create(GOOGLE_OUI, RTT_SUBCMD_SET_CONFIG); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + result = request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, numRttParams); + if (result < 0) { + return result; + } + nlattr *rtt_config = request.attr_start(RTT_ATTRIBUTE_TARGET_INFO); + for (unsigned i = 0; i < numRttParams; i++) { + + nlattr *attr2 = request.attr_start(i); + if (attr2 == NULL) { + return WIFI_ERROR_OUT_OF_MEMORY; + } + + result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, rttParams[i].addr); + if (result < 0) { + return result; + } + result = request.put_u8(RTT_ATTRIBUTE_TARGET_TYPE, rttParams[i].type); + if (result < 0) { + return result; + } + result = request.put_u8(RTT_ATTRIBUTE_TARGET_PEER, rttParams[i].peer); + if (result < 0) { + return result; + } + result = request.put(RTT_ATTRIBUTE_TARGET_CHAN, &rttParams[i].channel, + sizeof(wifi_channel_info)); + if (result < 0) { + return result; + } + result = request.put_u8(RTT_ATTRIBUTE_TARGET_MODE, rttParams[i].continuous); + if (result < 0) { + return result; + } + result = request.put_u32(RTT_ATTRIBUTE_TARGET_INTERVAL, rttParams[i].interval); + if (result < 0) { + return result; + } + result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT, + rttParams[i].num_measurements); + if (result < 0) { + return result; + } + result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_PKT, + rttParams[i].num_samples_per_measurement); + if (result < 0) { + return result; + } + result = request.put_u32(RTT_ATTRIBUTE_TARGET_NUM_RETRY, + rttParams[i].num_retries_per_measurement); + if (result < 0) { + return result; + } + request.attr_end(attr2); + } + + request.attr_end(rtt_config); + request.attr_end(data); + return WIFI_SUCCESS; + } + + int createTeardownRequest(WifiRequest& request, unsigned num_devices, mac_addr addr[]) { + int result = request.create(GOOGLE_OUI, RTT_SUBCMD_CANCEL_CONFIG); + if (result < 0) { + return result; + } + + nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); + request.put_u8(RTT_ATTRIBUTE_TARGET_CNT, num_devices); + for(unsigned i = 0; i < num_devices; i++) { + result = request.put_addr(RTT_ATTRIBUTE_TARGET_MAC, addr[i]); + if (result < 0) { + return result; + } + } + request.attr_end(data); + return result; + } + int start() { + //ALOGD("Setting RTT configuration"); + WifiRequest request(familyId(), ifaceId()); + int result = createSetupRequest(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create setup request; result = %d", result); + return result; + } + + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to configure RTT setup; result = %d", result); + return result; + } + + registerVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); + //ALOGI("Successfully started RTT operation"); + return result; + } + + virtual int cancel() { + //ALOGD("Stopping RTT"); + + WifiRequest request(familyId(), ifaceId()); + int result = createTeardownRequest(request, 0, NULL); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create stop request; result = %d", result); + } else { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to stop scan; result = %d", result); + } + } + + unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); + return WIFI_SUCCESS; + } + + int cancel_specific(unsigned num_devices, mac_addr addr[]) { + //ALOGD("Stopping scan"); + + WifiRequest request(familyId(), ifaceId()); + int result = createTeardownRequest(request, num_devices, addr); + if (result != WIFI_SUCCESS) { + ALOGE("failed to create stop request; result = %d", result); + } else { + result = requestResponse(request); + if (result != WIFI_SUCCESS) { + ALOGE("failed to stop RTT; result = %d", result); + } + } + + unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); + return WIFI_SUCCESS; + } + + virtual int handleResponse(WifiEvent& reply) { + /* Nothing to do on response! */ + return NL_SKIP; + } + + virtual int handleEvent(WifiEvent& event) { + //ALOGI("Got an RTT event"); + + // event.log(); + + nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA); + int len = event.get_vendor_data_len(); + + if (vendor_data == NULL || len == 0) { + //ALOGI("No rtt results found"); + } + + unregisterVendorHandler(GOOGLE_OUI, RTT_EVENT_COMPLETE); + wifi_unregister_cmd(wifiHandle(), id()); + + memset(rttResults, 0, sizeof(wifi_rtt_result) * MAX_RESULTS); + + int num = len / sizeof(wifi_rtt_result); + num = min(MAX_RESULTS, num); + memcpy(rttResults, event.get_vendor_data(), num * sizeof(wifi_rtt_result)); + //ALOGI("Retrieved %d rtt results", num); + + (*rttHandler.on_rtt_results)(id(), num, rttResults); + return NL_SKIP; + } +}; + + +/* API to request RTT measurement */ +wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface, + unsigned num_rtt_config, wifi_rtt_config rtt_config[], wifi_rtt_event_handler handler) +{ + wifi_handle handle = getWifiHandle(iface); + + RttCommand *cmd = new RttCommand(iface, id, num_rtt_config, rtt_config, handler); + wifi_register_cmd(handle, id, cmd); + return (wifi_error)cmd->start(); +} + +/* API to cancel RTT measurements */ +wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface, + unsigned num_devices, mac_addr addr[]) +{ + wifi_handle handle = getWifiHandle(iface); + RttCommand *cmd = (RttCommand *)wifi_unregister_cmd(handle, id); + if (cmd) { + cmd->cancel_specific(num_devices, addr); + cmd->releaseRef(); + return WIFI_SUCCESS; + } + + return WIFI_ERROR_INVALID_ARGS; +} + +/* API to get RTT capability */ +wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface, + wifi_rtt_capabilities *capabilities) +{ + GetRttCapabilitiesCommand command(iface, capabilities); + return (wifi_error) command.requestResponse(); +} + + |
