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.*/
42 typedef struct rssi_monitor_event_handler_s {
43     RSSIMonitorCommand* mRSSIMonitorCommandInstance;
44 } rssi_monitor_event_handlers;
45 
initializeRSSIMonitorHandler(hal_info * info)46 wifi_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 
cleanupRSSIMonitorHandler(hal_info * info)61 wifi_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 
enableEventHandling()78 void RSSIMonitorCommand::enableEventHandling()
79 {
80     pthread_mutex_lock(&rm_lock);
81     mEventHandlingEnabled = true;
82     pthread_mutex_unlock(&rm_lock);
83 }
84 
disableEventHandling()85 void RSSIMonitorCommand::disableEventHandling()
86 {
87     pthread_mutex_lock(&rm_lock);
88     mEventHandlingEnabled = false;
89     pthread_mutex_unlock(&rm_lock);
90 }
91 
isEventHandlingEnabled()92 bool 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 
setCallbackHandler(wifi_rssi_event_handler handler)102 void RSSIMonitorCommand::setCallbackHandler(wifi_rssi_event_handler handler)
103 {
104     mHandler = handler;
105 }
106 
RSSIMonitorCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)107 RSSIMonitorCommand::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 
~RSSIMonitorCommand()121 RSSIMonitorCommand::~RSSIMonitorCommand()
122 {
123     unregisterVendorHandler(mVendor_id, mSubcmd);
124     pthread_mutex_destroy(&rm_lock);
125 }
126 
setReqId(wifi_request_id reqid)127 void RSSIMonitorCommand::setReqId(wifi_request_id reqid)
128 {
129     mId = reqid;
130 }
131 
instance(wifi_handle handle,wifi_request_id id)132 RSSIMonitorCommand* 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  */
handleEvent(WifiEvent & event)172 int 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 
wifi_start_rssi_monitoring(wifi_request_id id,wifi_interface_handle iface,s8 max_rssi,s8 min_rssi,wifi_rssi_event_handler eh)252 wifi_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 
313 cleanup:
314     delete vCommand;
315     return ret;
316 }
317 
wifi_stop_rssi_monitoring(wifi_request_id id,wifi_interface_handle iface)318 wifi_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 
369 cleanup:
370     delete vCommand;
371     return ret;
372 }
373