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