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