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