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