1/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 *  * Redistributions of source code must retain the above copyright
7 *    notice, this list of conditions and the following disclaimer.
8 *  * Redistributions in binary form must reproduce the above copyright
9 *    notice, this list of conditions and the following disclaimer in
10 *    the documentation and/or other materials provided with the
11 *    distribution.
12 *  * Neither the name of The Linux Foundation nor the names of its
13 *    contributors may be used to endorse or promote products derived
14 *    from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "sync.h"
30
31#define LOG_TAG  "WifiHAL"
32
33#include <utils/Log.h>
34
35#include "wifi_hal.h"
36#include "common.h"
37#include "cpp_bindings.h"
38#include "rssi_monitor.h"
39#include "vendor_definitions.h"
40
41/* Used to handle rssi command events from driver/firmware.*/
42typedef struct rssi_monitor_event_handler_s {
43    RSSIMonitorCommand* mRSSIMonitorCommandInstance;
44} rssi_monitor_event_handlers;
45
46wifi_error initializeRSSIMonitorHandler(hal_info *info)
47{
48    info->rssi_handlers = (rssi_monitor_event_handlers *)malloc(sizeof(
49                              rssi_monitor_event_handlers));
50    if (info->rssi_handlers) {
51        memset(info->rssi_handlers, 0, sizeof(rssi_monitor_event_handlers));
52    }
53    else {
54        ALOGE("%s: Allocation of RSSI event handlers failed",
55              __FUNCTION__);
56        return WIFI_ERROR_OUT_OF_MEMORY;
57    }
58    return WIFI_SUCCESS;
59}
60
61wifi_error cleanupRSSIMonitorHandler(hal_info *info)
62{
63    rssi_monitor_event_handlers* event_handlers;
64    if (info && info->rssi_handlers) {
65        event_handlers = (rssi_monitor_event_handlers*) info->rssi_handlers;
66        if (event_handlers->mRSSIMonitorCommandInstance) {
67            delete event_handlers->mRSSIMonitorCommandInstance;
68        }
69        memset(event_handlers, 0, sizeof(rssi_monitor_event_handlers));
70        return WIFI_SUCCESS;
71    }
72    ALOGE ("%s: info or info->rssi_handlers NULL", __FUNCTION__);
73    return WIFI_ERROR_UNKNOWN;
74}
75
76void RSSIMonitorCommand::enableEventHandling()
77{
78    pthread_mutex_lock(&rm_lock);
79    mEventHandlingEnabled = true;
80    pthread_mutex_unlock(&rm_lock);
81}
82
83void RSSIMonitorCommand::disableEventHandling()
84{
85    pthread_mutex_lock(&rm_lock);
86    mEventHandlingEnabled = false;
87    pthread_mutex_unlock(&rm_lock);
88}
89
90bool RSSIMonitorCommand::isEventHandlingEnabled()
91{
92    bool eventHandlingEnabled;
93    pthread_mutex_lock(&rm_lock);
94    eventHandlingEnabled = mEventHandlingEnabled;
95    pthread_mutex_unlock(&rm_lock);
96
97    return eventHandlingEnabled;
98}
99
100void RSSIMonitorCommand::setCallbackHandler(wifi_rssi_event_handler handler)
101{
102    mHandler = handler;
103}
104
105RSSIMonitorCommand::RSSIMonitorCommand(wifi_handle handle, int id,
106                                       u32 vendor_id, u32 subcmd)
107        : WifiVendorCommand(handle, id, vendor_id, subcmd)
108{
109    memset(&mHandler, 0, sizeof(mHandler));
110    if (registerVendorHandler(vendor_id, subcmd)) {
111        /* Error case should not happen print log */
112        ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
113              __FUNCTION__, vendor_id, subcmd);
114    }
115    pthread_mutex_init(&rm_lock, NULL);
116    disableEventHandling();
117}
118
119RSSIMonitorCommand::~RSSIMonitorCommand()
120{
121    unregisterVendorHandler(mVendor_id, mSubcmd);
122    pthread_mutex_destroy(&rm_lock);
123}
124
125void RSSIMonitorCommand::setReqId(wifi_request_id reqid)
126{
127    mId = reqid;
128}
129
130RSSIMonitorCommand* RSSIMonitorCommand::instance(wifi_handle handle,
131                                                 wifi_request_id id)
132{
133    if (handle == NULL) {
134        ALOGE("Interface Handle is invalid");
135        return NULL;
136    }
137    hal_info *info = getHalInfo(handle);
138    if (!info || !info->rssi_handlers) {
139        ALOGE("rssi_handlers is invalid");
140        return NULL;
141    }
142
143    RSSIMonitorCommand* mRSSIMonitorCommandInstance =
144        info->rssi_handlers->mRSSIMonitorCommandInstance;
145
146    if (mRSSIMonitorCommandInstance == NULL) {
147        mRSSIMonitorCommandInstance = new RSSIMonitorCommand(handle, id,
148                OUI_QCA,
149                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
150        info->rssi_handlers->mRSSIMonitorCommandInstance = mRSSIMonitorCommandInstance;
151        return mRSSIMonitorCommandInstance;
152    }
153    else
154    {
155        if (handle != getWifiHandle(mRSSIMonitorCommandInstance->mInfo))
156        {
157            /* upper layer must have cleaned up the handle and reinitialized,
158               so we need to update the same */
159            ALOGV("Handle different, update the handle");
160            mRSSIMonitorCommandInstance->mInfo = (hal_info *)handle;
161        }
162        mRSSIMonitorCommandInstance->setReqId(id);
163    }
164    return mRSSIMonitorCommandInstance;
165}
166
167/* This function will be the main handler for incoming event.
168 * Call the appropriate callback handler after parsing the vendor data.
169 */
170int RSSIMonitorCommand::handleEvent(WifiEvent &event)
171{
172    int ret = WIFI_SUCCESS;
173
174    if (isEventHandlingEnabled() == false) {
175        ALOGE("%s: RSSI monitor isn't running or already stopped. "
176              "Nothing to do. Exit", __FUNCTION__);
177        return ret;
178    }
179
180    WifiVendorCommand::handleEvent(event);
181
182    /* Parse the vendordata and get the attribute */
183    switch(mSubcmd)
184    {
185        case QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI:
186        {
187            mac_addr addr;
188            s8 rssi;
189            wifi_request_id reqId;
190            struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX
191                                     + 1];
192            nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX,
193                    (struct nlattr *)mVendorData,
194                    mDataLen, NULL);
195
196            memset(addr, 0, sizeof(mac_addr));
197
198            if (!tb_vendor[
199                QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID])
200            {
201                ALOGE("%s: ATTR_RSSI_MONITORING_REQUEST_ID not found. Exit.",
202                    __FUNCTION__);
203                ret = WIFI_ERROR_INVALID_ARGS;
204                break;
205            }
206            reqId = nla_get_u32(
207                    tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID]
208                    );
209            /* If event has a different request_id, ignore that and use the
210             *  request_id value which we're maintaining.
211             */
212            if (reqId != id()) {
213                ALOGV("%s: Event has Req. ID:%d <> Ours:%d, continue...",
214                    __FUNCTION__, reqId, id());
215                reqId = id();
216            }
217            ret = get_mac_addr(tb_vendor,
218                    QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
219                    addr);
220            if (ret != WIFI_SUCCESS) {
221                return ret;
222            }
223            ALOGV(MAC_ADDR_STR, MAC_ADDR_ARRAY(addr));
224
225            if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI])
226            {
227                ALOGE("%s: QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI"
228                      " not found", __FUNCTION__);
229                return WIFI_ERROR_INVALID_ARGS;
230            }
231            rssi = get_s8(tb_vendor[
232                        QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI]);
233            ALOGV("Current RSSI : %d ", rssi);
234
235            if (mHandler.on_rssi_threshold_breached)
236                (*mHandler.on_rssi_threshold_breached)(reqId, addr, rssi);
237            else
238                ALOGE("RSSI Monitoring: No Callback registered: ");
239        }
240        break;
241
242        default:
243            /* Error case should not happen print log */
244            ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
245    }
246
247    return ret;
248}
249
250wifi_error wifi_start_rssi_monitoring(wifi_request_id id,
251                                      wifi_interface_handle iface,
252                                      s8 max_rssi,
253                                      s8 min_rssi,
254                                      wifi_rssi_event_handler eh)
255{
256    int ret = WIFI_SUCCESS;
257    struct nlattr *nlData;
258    WifiVendorCommand *vCommand = NULL;
259    wifi_handle wifiHandle = getWifiHandle(iface);
260    RSSIMonitorCommand *rssiCommand;
261
262    ret = initialize_vendor_cmd(iface, id,
263                                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
264                                &vCommand);
265    if (ret != WIFI_SUCCESS) {
266        ALOGE("%s: Initialization failed", __FUNCTION__);
267        return mapErrorKernelToWifiHAL(ret);
268    }
269
270    ALOGV("%s: Max RSSI:%d Min RSSI:%d", __FUNCTION__,
271          max_rssi, min_rssi);
272    /* Add the vendor specific attributes for the NL command. */
273    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
274    if (!nlData)
275        goto cleanup;
276
277    if (vCommand->put_u32(
278            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
279            QCA_WLAN_RSSI_MONITORING_START) ||
280        vCommand->put_u32(
281            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
282            id) ||
283        vCommand->put_s8(
284            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
285            max_rssi) ||
286        vCommand->put_s8(
287            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
288            min_rssi))
289    {
290        goto cleanup;
291    }
292
293    vCommand->attr_end(nlData);
294
295    rssiCommand = RSSIMonitorCommand::instance(wifiHandle, id);
296    if (rssiCommand == NULL) {
297        ALOGE("%s: Error rssiCommand NULL", __FUNCTION__);
298        return WIFI_ERROR_OUT_OF_MEMORY;
299    }
300
301    rssiCommand->setCallbackHandler(eh);
302
303    ret = vCommand->requestResponse();
304    if (ret < 0)
305        goto cleanup;
306
307    rssiCommand->enableEventHandling();
308
309cleanup:
310    delete vCommand;
311    return mapErrorKernelToWifiHAL(ret);
312}
313
314wifi_error wifi_stop_rssi_monitoring(wifi_request_id id,
315                                     wifi_interface_handle iface)
316{
317    int ret = WIFI_SUCCESS;
318    struct nlattr *nlData;
319    WifiVendorCommand *vCommand = NULL;
320    wifi_handle wifiHandle = getWifiHandle(iface);
321    RSSIMonitorCommand *rssiCommand;
322    rssi_monitor_event_handlers* event_handlers;
323    hal_info *info = getHalInfo(wifiHandle);
324
325    event_handlers = (rssi_monitor_event_handlers*)info->rssi_handlers;
326    rssiCommand = event_handlers->mRSSIMonitorCommandInstance;
327
328    if (rssiCommand == NULL ||
329        rssiCommand->isEventHandlingEnabled() == false) {
330        ALOGE("%s: RSSI monitor isn't running or already stopped. "
331            "Nothing to do. Exit", __FUNCTION__);
332        return WIFI_ERROR_NOT_AVAILABLE;
333    }
334
335    ret = initialize_vendor_cmd(iface, id,
336                                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
337                                &vCommand);
338    if (ret != WIFI_SUCCESS) {
339        ALOGE("%s: Initialization failed", __FUNCTION__);
340        return mapErrorKernelToWifiHAL(ret);
341    }
342
343    /* Add the vendor specific attributes for the NL command. */
344    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
345    if (!nlData)
346        goto cleanup;
347
348    if (vCommand->put_u32(
349            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
350            QCA_WLAN_RSSI_MONITORING_STOP) ||
351        vCommand->put_u32(
352            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
353            id))
354    {
355        goto cleanup;
356    }
357
358    vCommand->attr_end(nlData);
359
360    ret = vCommand->requestResponse();
361    if (ret < 0)
362        goto cleanup;
363
364    rssiCommand->disableEventHandling();
365
366
367cleanup:
368    delete vCommand;
369    return mapErrorKernelToWifiHAL(ret);
370}
371