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