1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <linux/pkt_sched.h>
19 #include <netlink/object-api.h>
20 #include <netlink-private/object-api.h>
21 #include <netlink-private/types.h>
22 #include <dlfcn.h>
23 #include <pthread.h>
24
25 #include "wifi_hal.h"
26 #include "common.h"
27 #include <errno.h>
28
getIfaceInfo(wifi_interface_handle handle)29 interface_info *getIfaceInfo(wifi_interface_handle handle)
30 {
31 return (interface_info *)handle;
32 }
33
getWifiHandle(wifi_interface_handle handle)34 wifi_handle getWifiHandle(wifi_interface_handle handle)
35 {
36 return getIfaceInfo(handle)->handle;
37 }
38
getHalInfo(wifi_handle handle)39 hal_info *getHalInfo(wifi_handle handle)
40 {
41 return (hal_info *)handle;
42 }
43
getHalInfo(wifi_interface_handle handle)44 hal_info *getHalInfo(wifi_interface_handle handle)
45 {
46 return getHalInfo(getWifiHandle(handle));
47 }
48
getWifiHandle(hal_info * info)49 wifi_handle getWifiHandle(hal_info *info)
50 {
51 return (wifi_handle)info;
52 }
53
getIfaceHandle(interface_info * info)54 wifi_interface_handle getIfaceHandle(interface_info *info)
55 {
56 return (wifi_interface_handle)info;
57 }
58
wifi_register_handler(wifi_handle handle,int cmd,nl_recvmsg_msg_cb_t func,void * arg)59 wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
60 {
61 hal_info *info = (hal_info *)handle;
62
63 pthread_mutex_lock(&info->cb_lock);
64
65 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
66
67 for (int i = 0; i < info->num_event_cb; i++) {
68 if(info->event_cb[i].nl_cmd == cmd &&
69 info->event_cb[i].cb_arg == arg) {
70 info->event_cb[i].cb_func = func;
71 ALOGV("Updated event handler %p for nl_cmd 0x%0x"
72 " and arg %p", func, cmd, arg);
73 pthread_mutex_unlock(&info->cb_lock);
74 return WIFI_SUCCESS;
75 }
76 }
77
78 if (info->num_event_cb < info->alloc_event_cb) {
79 info->event_cb[info->num_event_cb].nl_cmd = cmd;
80 info->event_cb[info->num_event_cb].vendor_id = 0;
81 info->event_cb[info->num_event_cb].vendor_subcmd = 0;
82 info->event_cb[info->num_event_cb].cb_func = func;
83 info->event_cb[info->num_event_cb].cb_arg = arg;
84 info->num_event_cb++;
85 ALOGV("Successfully added event handler %p for command %d", func, cmd);
86 result = WIFI_SUCCESS;
87 } else {
88 result = WIFI_ERROR_OUT_OF_MEMORY;
89 }
90
91 pthread_mutex_unlock(&info->cb_lock);
92 return result;
93 }
94
wifi_register_vendor_handler(wifi_handle handle,uint32_t id,int subcmd,nl_recvmsg_msg_cb_t func,void * arg)95 wifi_error wifi_register_vendor_handler(wifi_handle handle,
96 uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
97 {
98 hal_info *info = (hal_info *)handle;
99
100 pthread_mutex_lock(&info->cb_lock);
101
102 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
103
104 for (int i = 0; i < info->num_event_cb; i++) {
105 if(info->event_cb[i].vendor_id == id &&
106 info->event_cb[i].vendor_subcmd == subcmd)
107 {
108 info->event_cb[i].cb_func = func;
109 info->event_cb[i].cb_arg = arg;
110 ALOGV("Updated event handler %p for vendor 0x%0x, subcmd 0x%0x"
111 " and arg %p", func, id, subcmd, arg);
112 pthread_mutex_unlock(&info->cb_lock);
113 return WIFI_SUCCESS;
114 }
115 }
116
117 if (info->num_event_cb < info->alloc_event_cb) {
118 info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR;
119 info->event_cb[info->num_event_cb].vendor_id = id;
120 info->event_cb[info->num_event_cb].vendor_subcmd = subcmd;
121 info->event_cb[info->num_event_cb].cb_func = func;
122 info->event_cb[info->num_event_cb].cb_arg = arg;
123 info->num_event_cb++;
124 ALOGV("Added event handler %p for vendor 0x%0x, subcmd 0x%0x and arg"
125 " %p", func, id, subcmd, arg);
126 result = WIFI_SUCCESS;
127 } else {
128 result = WIFI_ERROR_OUT_OF_MEMORY;
129 }
130
131 pthread_mutex_unlock(&info->cb_lock);
132 return result;
133 }
134
wifi_unregister_handler(wifi_handle handle,int cmd)135 void wifi_unregister_handler(wifi_handle handle, int cmd)
136 {
137 hal_info *info = (hal_info *)handle;
138
139 if (cmd == NL80211_CMD_VENDOR) {
140 ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
141 return;
142 }
143
144 pthread_mutex_lock(&info->cb_lock);
145
146 for (int i = 0; i < info->num_event_cb; i++) {
147 if (info->event_cb[i].nl_cmd == cmd) {
148 if(i < info->num_event_cb-1) {
149 /* No need to memmove if only one entry exist and deleting
150 * the same, as the num_event_cb will become 0 in this case.
151 */
152 memmove(&info->event_cb[i], &info->event_cb[i+1],
153 (info->num_event_cb - i) * sizeof(cb_info));
154 }
155 info->num_event_cb--;
156 ALOGV("Successfully removed event handler for command %d", cmd);
157 break;
158 }
159 }
160
161 pthread_mutex_unlock(&info->cb_lock);
162 }
163
wifi_unregister_vendor_handler(wifi_handle handle,uint32_t id,int subcmd)164 void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
165 {
166 hal_info *info = (hal_info *)handle;
167
168 pthread_mutex_lock(&info->cb_lock);
169
170 for (int i = 0; i < info->num_event_cb; i++) {
171
172 if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
173 && info->event_cb[i].vendor_id == id
174 && info->event_cb[i].vendor_subcmd == subcmd) {
175 if(i < info->num_event_cb-1) {
176 /* No need to memmove if only one entry exist and deleting
177 * the same, as the num_event_cb will become 0 in this case.
178 */
179 memmove(&info->event_cb[i], &info->event_cb[i+1],
180 (info->num_event_cb - i) * sizeof(cb_info));
181 }
182 info->num_event_cb--;
183 ALOGV("Successfully removed event handler for vendor 0x%0x", id);
184 break;
185 }
186 }
187
188 pthread_mutex_unlock(&info->cb_lock);
189 }
190
191
wifi_register_cmd(wifi_handle handle,int id,WifiCommand * cmd)192 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
193 {
194 hal_info *info = (hal_info *)handle;
195
196 if (info->num_cmd < info->alloc_cmd) {
197 info->cmd[info->num_cmd].id = id;
198 info->cmd[info->num_cmd].cmd = cmd;
199 info->num_cmd++;
200 ALOGV("Successfully added command %d: %p", id, cmd);
201 return WIFI_SUCCESS;
202 } else {
203 return WIFI_ERROR_OUT_OF_MEMORY;
204 }
205 }
206
wifi_unregister_cmd(wifi_handle handle,int id)207 WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
208 {
209 hal_info *info = (hal_info *)handle;
210
211 for (int i = 0; i < info->num_cmd; i++) {
212 if (info->cmd[i].id == id) {
213 WifiCommand *cmd = info->cmd[i].cmd;
214 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
215 info->num_cmd--;
216 ALOGV("Successfully removed command %d: %p", id, cmd);
217 return cmd;
218 }
219 }
220
221 return NULL;
222 }
223
wifi_unregister_cmd(wifi_handle handle,WifiCommand * cmd)224 void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
225 {
226 hal_info *info = (hal_info *)handle;
227
228 for (int i = 0; i < info->num_cmd; i++) {
229 if (info->cmd[i].cmd == cmd) {
230 int id = info->cmd[i].id;
231 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
232 info->num_cmd--;
233 ALOGV("Successfully removed command %d: %p", id, cmd);
234 return;
235 }
236 }
237 }
238
239 #ifdef __cplusplus
240 extern "C"
241 {
242 #endif /* __cplusplus */
243
hexdump(void * buf,u16 len)244 void hexdump(void *buf, u16 len)
245 {
246 int i=0;
247 char *bytes = (char *)buf;
248
249 if (len) {
250 ALOGV("******HexDump len:%d*********", len);
251 for (i = 0; ((i + 7) < len); i+=8) {
252 ALOGV("%02x %02x %02x %02x %02x %02x %02x %02x",
253 bytes[i], bytes[i+1],
254 bytes[i+2], bytes[i+3],
255 bytes[i+4], bytes[i+5],
256 bytes[i+6], bytes[i+7]);
257 }
258 if ((len - i) >= 4) {
259 ALOGV("%02x %02x %02x %02x",
260 bytes[i], bytes[i+1],
261 bytes[i+2], bytes[i+3]);
262 i+=4;
263 }
264 for (;i < len;i++) {
265 ALOGV("%02x", bytes[i]);
266 }
267 ALOGV("******HexDump End***********");
268 } else {
269 return;
270 }
271 }
272
273 /* Firmware sends RSSI value without noise floor.
274 * Add noise floor to the same and return absolute values.
275 */
get_rssi(u8 rssi_wo_noise_floor)276 u8 get_rssi(u8 rssi_wo_noise_floor)
277 {
278 return abs((int)rssi_wo_noise_floor - 96);
279 }
280
281 #ifdef __cplusplus
282 }
283 #endif /* __cplusplus */
284
285 /* Pointer to the table of LOWI callback funcs */
286 lowi_cb_table_t *LowiWifiHalApi = NULL;
287 /* LowiSupportedCapabilities read */
288 u32 lowiSupportedCapabilities = 0;
289
compareLowiVersion(u16 major,u16 minor,u16 micro)290 int compareLowiVersion(u16 major, u16 minor, u16 micro)
291 {
292 u32 currVersion = 0x10000*(WIFIHAL_LOWI_MAJOR_VERSION) + \
293 0x100*(WIFIHAL_LOWI_MINOR_VERSION) + \
294 WIFIHAL_LOWI_MICRO_VERSION;
295
296 u32 lowiVersion = 0x10000*(major) + \
297 0x100*(minor) + \
298 micro;
299
300 return (memcmp(&currVersion, &lowiVersion, sizeof(u32)));
301 }
302
303 /*
304 * This function will open the lowi shared library and obtain the
305 * Lowi Callback table and the capabilities supported.
306 * A version check is also performed in this function and if the version
307 * check fails then the callback table returned will be NULL.
308 */
fetchLowiCbTableAndCapabilities(lowi_cb_table_t ** lowi_wifihal_api,bool * lowi_get_capa_supported)309 wifi_error fetchLowiCbTableAndCapabilities(lowi_cb_table_t **lowi_wifihal_api,
310 bool *lowi_get_capa_supported)
311 {
312 getCbTable_t* lowiCbTable = NULL;
313 int ret = 0;
314 wifi_error retVal = WIFI_SUCCESS;
315
316 *lowi_wifihal_api = NULL;
317 *lowi_get_capa_supported = false;
318
319 #if __WORDSIZE == 64
320 void* lowi_handle = dlopen("/vendor/lib64/liblowi_wifihal.so", RTLD_NOW);
321 #else
322 void* lowi_handle = dlopen("/vendor/lib/liblowi_wifihal.so", RTLD_NOW);
323 #endif
324 if (!lowi_handle) {
325 ALOGE("%s: NULL lowi_handle, err: %s", __FUNCTION__, dlerror());
326 return WIFI_ERROR_UNKNOWN;
327 }
328
329 lowiCbTable = (getCbTable_t*)dlsym(lowi_handle,
330 "lowi_wifihal_get_cb_table");
331 if (!lowiCbTable) {
332 ALOGE("%s: NULL lowi callback table", __FUNCTION__);
333 return WIFI_ERROR_UNKNOWN;
334 }
335
336 *lowi_wifihal_api = lowiCbTable();
337
338 /* First check whether lowi module implements the get_lowi_version
339 * function. All the functions in lowi module starts with
340 * "lowi_wifihal_" prefix thus the below function name.
341 */
342 if ((dlsym(lowi_handle, "lowi_wifihal_get_lowi_version") != NULL) &&
343 ((*lowi_wifihal_api)->get_lowi_version != NULL)) {
344 u16 lowiMajorVersion = WIFIHAL_LOWI_MAJOR_VERSION;
345 u16 lowiMinorVersion = WIFIHAL_LOWI_MINOR_VERSION;
346 u16 lowiMicroVersion = WIFIHAL_LOWI_MICRO_VERSION;
347 int versionCheck = -1;
348
349 ret = (*lowi_wifihal_api)->get_lowi_version(&lowiMajorVersion,
350 &lowiMinorVersion,
351 &lowiMicroVersion);
352 if (ret) {
353 ALOGE("%s: get_lowi_version returned error:%d",
354 __FUNCTION__, ret);
355 retVal = WIFI_ERROR_NOT_SUPPORTED;
356 goto cleanup;
357 }
358 ALOGV("%s: Lowi version:%d.%d.%d", __FUNCTION__,
359 lowiMajorVersion, lowiMinorVersion,
360 lowiMicroVersion);
361
362 /* Compare the version with version in wifihal_internal.h */
363 versionCheck = compareLowiVersion(lowiMajorVersion,
364 lowiMinorVersion,
365 lowiMicroVersion);
366 if (versionCheck < 0) {
367 ALOGE("%s: Version Check failed:%d", __FUNCTION__,
368 versionCheck);
369 retVal = WIFI_ERROR_NOT_SUPPORTED;
370 goto cleanup;
371 }
372 }
373 else {
374 ALOGV("%s: lowi_wifihal_get_lowi_version not present",
375 __FUNCTION__);
376 }
377
378
379 /* Check if get_lowi_capabilities func pointer exists in
380 * the lowi lib and populate lowi_get_capa_supported
381 * All the functions in lowi modules starts with
382 * "lowi_wifihal_ prefix" thus the below function name.
383 */
384 if (dlsym(lowi_handle, "lowi_wifihal_get_lowi_capabilities") != NULL) {
385 *lowi_get_capa_supported = true;
386 }
387 else {
388 ALOGV("lowi_wifihal_get_lowi_capabilities() is not supported.");
389 *lowi_get_capa_supported = false;
390 }
391 cleanup:
392 if (retVal) {
393 *lowi_wifihal_api = NULL;
394 }
395 return retVal;
396 }
397
getLowiCallbackTable(u32 requested_lowi_capabilities)398 lowi_cb_table_t *getLowiCallbackTable(u32 requested_lowi_capabilities)
399 {
400 int ret = WIFI_SUCCESS;
401 bool lowi_get_capabilities_support = false;
402
403 if (LowiWifiHalApi == NULL) {
404 ALOGV("%s: LowiWifiHalApi Null, Initialize Lowi",
405 __FUNCTION__);
406 ret = fetchLowiCbTableAndCapabilities(&LowiWifiHalApi,
407 &lowi_get_capabilities_support);
408 if (ret != WIFI_SUCCESS || LowiWifiHalApi == NULL ||
409 LowiWifiHalApi->init == NULL) {
410 ALOGE("%s: LOWI is not supported.", __FUNCTION__);
411 goto cleanup;
412 }
413 /* Initialize LOWI if it isn't up already. */
414 ret = LowiWifiHalApi->init();
415 if (ret) {
416 ALOGE("%s: failed lowi initialization. "
417 "Returned error:%d. Exit.", __FUNCTION__, ret);
418 goto cleanup;
419 }
420 if (!lowi_get_capabilities_support ||
421 LowiWifiHalApi->get_lowi_capabilities == NULL) {
422 ALOGV("%s: Allow rtt APIs thru LOWI to proceed even though "
423 "get_lowi_capabilities() is not supported. Returning",
424 __FUNCTION__);
425 lowiSupportedCapabilities |=
426 (ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
427 return LowiWifiHalApi;
428 }
429 ret =
430 LowiWifiHalApi->get_lowi_capabilities(&lowiSupportedCapabilities);
431 if (ret) {
432 ALOGV("%s: failed to get lowi supported capabilities."
433 "Returned error:%d. Exit.", __FUNCTION__, ret);
434 goto cleanup;
435 }
436 }
437
438 if ((lowiSupportedCapabilities & requested_lowi_capabilities) == 0) {
439 return NULL;
440 }
441 return LowiWifiHalApi;
442
443 cleanup:
444 if (LowiWifiHalApi && LowiWifiHalApi->destroy) {
445 ret = LowiWifiHalApi->destroy();
446 }
447 LowiWifiHalApi = NULL;
448 lowiSupportedCapabilities = 0;
449 return LowiWifiHalApi;
450 }
451
mapErrorKernelToWifiHAL(int error)452 wifi_error mapErrorKernelToWifiHAL(int error)
453 {
454 if (error >= 0)
455 return WIFI_ERROR_NONE;
456
457 switch (error) {
458 case -EOPNOTSUPP:
459 return WIFI_ERROR_NOT_SUPPORTED;
460 case -EAGAIN:
461 return WIFI_ERROR_NOT_AVAILABLE;
462 case -EINVAL:
463 return WIFI_ERROR_INVALID_ARGS;
464 case -ETIMEDOUT:
465 return WIFI_ERROR_TIMED_OUT;
466 case -ENOMEM:
467 return WIFI_ERROR_OUT_OF_MEMORY;
468 case -EBUSY:
469 return WIFI_ERROR_BUSY;
470 default:
471 return WIFI_ERROR_UNKNOWN;
472 }
473 return WIFI_ERROR_UNKNOWN;
474 }
475