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