1/* Copyright (c) 2015, 2018 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        free(info->rssi_handlers);
71        info->rssi_handlers = NULL;
72        return WIFI_SUCCESS;
73    }
74    ALOGE ("%s: info or info->rssi_handlers NULL", __FUNCTION__);
75    return WIFI_ERROR_UNKNOWN;
76}
77
78void RSSIMonitorCommand::enableEventHandling()
79{
80    pthread_mutex_lock(&rm_lock);
81    mEventHandlingEnabled = true;
82    pthread_mutex_unlock(&rm_lock);
83}
84
85void RSSIMonitorCommand::disableEventHandling()
86{
87    pthread_mutex_lock(&rm_lock);
88    mEventHandlingEnabled = false;
89    pthread_mutex_unlock(&rm_lock);
90}
91
92bool RSSIMonitorCommand::isEventHandlingEnabled()
93{
94    bool eventHandlingEnabled;
95    pthread_mutex_lock(&rm_lock);
96    eventHandlingEnabled = mEventHandlingEnabled;
97    pthread_mutex_unlock(&rm_lock);
98
99    return eventHandlingEnabled;
100}
101
102void RSSIMonitorCommand::setCallbackHandler(wifi_rssi_event_handler handler)
103{
104    mHandler = handler;
105}
106
107RSSIMonitorCommand::RSSIMonitorCommand(wifi_handle handle, int id,
108                                       u32 vendor_id, u32 subcmd)
109        : WifiVendorCommand(handle, id, vendor_id, subcmd)
110{
111    memset(&mHandler, 0, sizeof(mHandler));
112    if (registerVendorHandler(vendor_id, subcmd)) {
113        /* Error case should not happen print log */
114        ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
115              __FUNCTION__, vendor_id, subcmd);
116    }
117    pthread_mutex_init(&rm_lock, NULL);
118    disableEventHandling();
119}
120
121RSSIMonitorCommand::~RSSIMonitorCommand()
122{
123    unregisterVendorHandler(mVendor_id, mSubcmd);
124    pthread_mutex_destroy(&rm_lock);
125}
126
127void RSSIMonitorCommand::setReqId(wifi_request_id reqid)
128{
129    mId = reqid;
130}
131
132RSSIMonitorCommand* RSSIMonitorCommand::instance(wifi_handle handle,
133                                                 wifi_request_id id)
134{
135    if (handle == NULL) {
136        ALOGE("Interface Handle is invalid");
137        return NULL;
138    }
139    hal_info *info = getHalInfo(handle);
140    if (!info || !info->rssi_handlers) {
141        ALOGE("rssi_handlers is invalid");
142        return NULL;
143    }
144
145    RSSIMonitorCommand* mRSSIMonitorCommandInstance =
146        info->rssi_handlers->mRSSIMonitorCommandInstance;
147
148    if (mRSSIMonitorCommandInstance == NULL) {
149        mRSSIMonitorCommandInstance = new RSSIMonitorCommand(handle, id,
150                OUI_QCA,
151                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
152        info->rssi_handlers->mRSSIMonitorCommandInstance = mRSSIMonitorCommandInstance;
153        return mRSSIMonitorCommandInstance;
154    }
155    else
156    {
157        if (handle != getWifiHandle(mRSSIMonitorCommandInstance->mInfo))
158        {
159            /* upper layer must have cleaned up the handle and reinitialized,
160               so we need to update the same */
161            ALOGV("Handle different, update the handle");
162            mRSSIMonitorCommandInstance->mInfo = (hal_info *)handle;
163        }
164        mRSSIMonitorCommandInstance->setReqId(id);
165    }
166    return mRSSIMonitorCommandInstance;
167}
168
169/* This function will be the main handler for incoming event.
170 * Call the appropriate callback handler after parsing the vendor data.
171 */
172int RSSIMonitorCommand::handleEvent(WifiEvent &event)
173{
174    int ret = WIFI_SUCCESS;
175
176    if (isEventHandlingEnabled() == false) {
177        ALOGE("%s: RSSI monitor isn't running or already stopped. "
178              "Nothing to do. Exit", __FUNCTION__);
179        return ret;
180    }
181
182    WifiVendorCommand::handleEvent(event);
183
184    /* Parse the vendordata and get the attribute */
185    switch(mSubcmd)
186    {
187        case QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI:
188        {
189            mac_addr addr;
190            s8 rssi;
191            wifi_request_id reqId;
192            struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX
193                                     + 1];
194            nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX,
195                    (struct nlattr *)mVendorData,
196                    mDataLen, NULL);
197
198            memset(addr, 0, sizeof(mac_addr));
199
200            if (!tb_vendor[
201                QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID])
202            {
203                ALOGE("%s: ATTR_RSSI_MONITORING_REQUEST_ID not found. Exit.",
204                    __FUNCTION__);
205                ret = WIFI_ERROR_INVALID_ARGS;
206                break;
207            }
208            reqId = nla_get_u32(
209                    tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID]
210                    );
211            /* If event has a different request_id, ignore that and use the
212             *  request_id value which we're maintaining.
213             */
214            if (reqId != id()) {
215                ALOGV("%s: Event has Req. ID:%d <> Ours:%d, continue...",
216                    __FUNCTION__, reqId, id());
217                reqId = id();
218            }
219            ret = get_mac_addr(tb_vendor,
220                    QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
221                    addr);
222            if (ret != WIFI_SUCCESS) {
223                return ret;
224            }
225            ALOGV(MAC_ADDR_STR, MAC_ADDR_ARRAY(addr));
226
227            if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI])
228            {
229                ALOGE("%s: QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI"
230                      " not found", __FUNCTION__);
231                return WIFI_ERROR_INVALID_ARGS;
232            }
233            rssi = get_s8(tb_vendor[
234                        QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI]);
235            ALOGV("Current RSSI : %d ", rssi);
236
237            if (mHandler.on_rssi_threshold_breached)
238                (*mHandler.on_rssi_threshold_breached)(reqId, addr, rssi);
239            else
240                ALOGE("RSSI Monitoring: No Callback registered: ");
241        }
242        break;
243
244        default:
245            /* Error case should not happen print log */
246            ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
247    }
248
249    return ret;
250}
251
252wifi_error wifi_start_rssi_monitoring(wifi_request_id id,
253                                      wifi_interface_handle iface,
254                                      s8 max_rssi,
255                                      s8 min_rssi,
256                                      wifi_rssi_event_handler eh)
257{
258    wifi_error ret;
259    struct nlattr *nlData;
260    WifiVendorCommand *vCommand = NULL;
261    wifi_handle wifiHandle = getWifiHandle(iface);
262    RSSIMonitorCommand *rssiCommand;
263
264    ret = initialize_vendor_cmd(iface, id,
265                                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
266                                &vCommand);
267    if (ret != WIFI_SUCCESS) {
268        ALOGE("%s: Initialization failed", __FUNCTION__);
269        return ret;
270    }
271
272    ALOGV("%s: Max RSSI:%d Min RSSI:%d", __FUNCTION__,
273          max_rssi, min_rssi);
274    /* Add the vendor specific attributes for the NL command. */
275    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
276    if (!nlData)
277        goto cleanup;
278
279    ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
280                             QCA_WLAN_RSSI_MONITORING_START);
281    if (ret != WIFI_SUCCESS)
282        goto cleanup;
283    ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
284                            id);
285    if (ret != WIFI_SUCCESS)
286        goto cleanup;
287    ret = vCommand->put_s8(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
288                           max_rssi);
289    if (ret != WIFI_SUCCESS)
290        goto cleanup;
291    ret = vCommand->put_s8(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
292                           min_rssi);
293    if (ret != WIFI_SUCCESS)
294        goto cleanup;
295
296    vCommand->attr_end(nlData);
297
298    rssiCommand = RSSIMonitorCommand::instance(wifiHandle, id);
299    if (rssiCommand == NULL) {
300        ALOGE("%s: Error rssiCommand NULL", __FUNCTION__);
301        ret = WIFI_ERROR_OUT_OF_MEMORY;
302        goto cleanup;
303    }
304
305    rssiCommand->setCallbackHandler(eh);
306
307    ret = vCommand->requestResponse();
308    if (ret != WIFI_SUCCESS)
309        goto cleanup;
310
311    rssiCommand->enableEventHandling();
312
313cleanup:
314    delete vCommand;
315    return ret;
316}
317
318wifi_error wifi_stop_rssi_monitoring(wifi_request_id id,
319                                     wifi_interface_handle iface)
320{
321    wifi_error ret;
322    struct nlattr *nlData;
323    WifiVendorCommand *vCommand = NULL;
324    wifi_handle wifiHandle = getWifiHandle(iface);
325    RSSIMonitorCommand *rssiCommand;
326    rssi_monitor_event_handlers* event_handlers;
327    hal_info *info = getHalInfo(wifiHandle);
328
329    event_handlers = info->rssi_handlers;
330    rssiCommand = event_handlers->mRSSIMonitorCommandInstance;
331
332    if (rssiCommand == NULL ||
333        rssiCommand->isEventHandlingEnabled() == false) {
334        ALOGE("%s: RSSI monitor isn't running or already stopped. "
335            "Nothing to do. Exit", __FUNCTION__);
336        return WIFI_ERROR_NOT_AVAILABLE;
337    }
338
339    ret = initialize_vendor_cmd(iface, id,
340                                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
341                                &vCommand);
342    if (ret != WIFI_SUCCESS) {
343        ALOGE("%s: Initialization failed", __FUNCTION__);
344        return ret;
345    }
346
347    /* Add the vendor specific attributes for the NL command. */
348    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
349    if (!nlData)
350        goto cleanup;
351
352    ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
353                            QCA_WLAN_RSSI_MONITORING_STOP);
354    if (ret != WIFI_SUCCESS)
355        goto cleanup;
356    ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
357                            id);
358    if (ret != WIFI_SUCCESS)
359        goto cleanup;
360
361    vCommand->attr_end(nlData);
362
363    ret = vCommand->requestResponse();
364    if (ret != WIFI_SUCCESS)
365        goto cleanup;
366
367    rssiCommand->disableEventHandling();
368
369cleanup:
370    delete vCommand;
371    return ret;
372}
373