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-types.h>
21 #include <dlfcn.h>
22
23 #include "wifi_hal.h"
24 #include "common.h"
25 #include <netlink-types.h>
26
getIfaceInfo(wifi_interface_handle handle)27 interface_info *getIfaceInfo(wifi_interface_handle handle)
28 {
29 return (interface_info *)handle;
30 }
31
getWifiHandle(wifi_interface_handle handle)32 wifi_handle getWifiHandle(wifi_interface_handle handle)
33 {
34 return getIfaceInfo(handle)->handle;
35 }
36
getHalInfo(wifi_handle handle)37 hal_info *getHalInfo(wifi_handle handle)
38 {
39 return (hal_info *)handle;
40 }
41
getHalInfo(wifi_interface_handle handle)42 hal_info *getHalInfo(wifi_interface_handle handle)
43 {
44 return getHalInfo(getWifiHandle(handle));
45 }
46
getWifiHandle(hal_info * info)47 wifi_handle getWifiHandle(hal_info *info)
48 {
49 return (wifi_handle)info;
50 }
51
getIfaceHandle(interface_info * info)52 wifi_interface_handle getIfaceHandle(interface_info *info)
53 {
54 return (wifi_interface_handle)info;
55 }
56
wifi_register_handler(wifi_handle handle,int cmd,nl_recvmsg_msg_cb_t func,void * arg)57 wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
58 {
59 hal_info *info = (hal_info *)handle;
60
61 pthread_mutex_lock(&info->cb_lock);
62
63 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
64
65 for (int i = 0; i < info->num_event_cb; i++) {
66 if(info->event_cb[i].nl_cmd == cmd &&
67 info->event_cb[i].cb_arg == arg) {
68 info->event_cb[i].cb_func = func;
69 ALOGI("Updated event handler %p for nl_cmd 0x%0x"
70 " and arg %p", func, cmd, arg);
71 pthread_mutex_unlock(&info->cb_lock);
72 return WIFI_SUCCESS;
73 }
74 }
75
76 if (info->num_event_cb < info->alloc_event_cb) {
77 info->event_cb[info->num_event_cb].nl_cmd = cmd;
78 info->event_cb[info->num_event_cb].vendor_id = 0;
79 info->event_cb[info->num_event_cb].vendor_subcmd = 0;
80 info->event_cb[info->num_event_cb].cb_func = func;
81 info->event_cb[info->num_event_cb].cb_arg = arg;
82 info->num_event_cb++;
83 ALOGI("Successfully added event handler %p for command %d", func, cmd);
84 result = WIFI_SUCCESS;
85 } else {
86 result = WIFI_ERROR_OUT_OF_MEMORY;
87 }
88
89 pthread_mutex_unlock(&info->cb_lock);
90 return result;
91 }
92
wifi_register_vendor_handler(wifi_handle handle,uint32_t id,int subcmd,nl_recvmsg_msg_cb_t func,void * arg)93 wifi_error wifi_register_vendor_handler(wifi_handle handle,
94 uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
95 {
96 hal_info *info = (hal_info *)handle;
97
98 pthread_mutex_lock(&info->cb_lock);
99
100 wifi_error result = WIFI_ERROR_OUT_OF_MEMORY;
101
102 for (int i = 0; i < info->num_event_cb; i++) {
103 if(info->event_cb[i].vendor_id == id &&
104 info->event_cb[i].vendor_subcmd == subcmd)
105 {
106 info->event_cb[i].cb_func = func;
107 info->event_cb[i].cb_arg = arg;
108 ALOGI("Updated event handler %p for vendor 0x%0x, subcmd 0x%0x"
109 " and arg %p", func, id, subcmd, arg);
110 pthread_mutex_unlock(&info->cb_lock);
111 return WIFI_SUCCESS;
112 }
113 }
114
115 if (info->num_event_cb < info->alloc_event_cb) {
116 info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR;
117 info->event_cb[info->num_event_cb].vendor_id = id;
118 info->event_cb[info->num_event_cb].vendor_subcmd = subcmd;
119 info->event_cb[info->num_event_cb].cb_func = func;
120 info->event_cb[info->num_event_cb].cb_arg = arg;
121 info->num_event_cb++;
122 ALOGI("Added event handler %p for vendor 0x%0x, subcmd 0x%0x and arg"
123 " %p", func, id, subcmd, arg);
124 result = WIFI_SUCCESS;
125 } else {
126 result = WIFI_ERROR_OUT_OF_MEMORY;
127 }
128
129 pthread_mutex_unlock(&info->cb_lock);
130 return result;
131 }
132
wifi_unregister_handler(wifi_handle handle,int cmd)133 void wifi_unregister_handler(wifi_handle handle, int cmd)
134 {
135 hal_info *info = (hal_info *)handle;
136
137 if (cmd == NL80211_CMD_VENDOR) {
138 ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
139 return;
140 }
141
142 pthread_mutex_lock(&info->cb_lock);
143
144 for (int i = 0; i < info->num_event_cb; i++) {
145 if (info->event_cb[i].nl_cmd == cmd) {
146 if(i < info->num_event_cb-1) {
147 /* No need to memmove if only one entry exist and deleting
148 * the same, as the num_event_cb will become 0 in this case.
149 */
150 memmove(&info->event_cb[i], &info->event_cb[i+1],
151 (info->num_event_cb - i) * sizeof(cb_info));
152 }
153 info->num_event_cb--;
154 ALOGI("Successfully removed event handler for command %d", cmd);
155 break;
156 }
157 }
158
159 pthread_mutex_unlock(&info->cb_lock);
160 }
161
wifi_unregister_vendor_handler(wifi_handle handle,uint32_t id,int subcmd)162 void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
163 {
164 hal_info *info = (hal_info *)handle;
165
166 pthread_mutex_lock(&info->cb_lock);
167
168 for (int i = 0; i < info->num_event_cb; i++) {
169
170 if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
171 && info->event_cb[i].vendor_id == id
172 && info->event_cb[i].vendor_subcmd == subcmd) {
173 if(i < info->num_event_cb-1) {
174 /* No need to memmove if only one entry exist and deleting
175 * the same, as the num_event_cb will become 0 in this case.
176 */
177 memmove(&info->event_cb[i], &info->event_cb[i+1],
178 (info->num_event_cb - i) * sizeof(cb_info));
179 }
180 info->num_event_cb--;
181 ALOGI("Successfully removed event handler for vendor 0x%0x", id);
182 break;
183 }
184 }
185
186 pthread_mutex_unlock(&info->cb_lock);
187 }
188
189
wifi_register_cmd(wifi_handle handle,int id,WifiCommand * cmd)190 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
191 {
192 hal_info *info = (hal_info *)handle;
193
194 ALOGD("registering command %d", id);
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 ALOGI("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 ALOGD("un-registering command %d", id);
212
213 for (int i = 0; i < info->num_cmd; i++) {
214 if (info->cmd[i].id == id) {
215 WifiCommand *cmd = info->cmd[i].cmd;
216 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
217 info->num_cmd--;
218 ALOGI("Successfully removed command %d: %p", id, cmd);
219 return cmd;
220 }
221 }
222
223 return NULL;
224 }
225
wifi_unregister_cmd(wifi_handle handle,WifiCommand * cmd)226 void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
227 {
228 hal_info *info = (hal_info *)handle;
229
230 for (int i = 0; i < info->num_cmd; i++) {
231 if (info->cmd[i].cmd == cmd) {
232 int id = info->cmd[i].id;
233 memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
234 info->num_cmd--;
235 ALOGI("Successfully removed command %d: %p", id, cmd);
236 return;
237 }
238 }
239 }
240
241 #ifdef __cplusplus
242 extern "C"
243 {
244 #endif /* __cplusplus */
245
hexdump(void * buf,u16 len)246 void hexdump(void *buf, u16 len)
247 {
248 int i=0;
249 char *bytes = (char *)buf;
250 ALOGI("******HexDump len:%d*********", len);
251 for (i = 0; ((i + 7) < len); i+=8) {
252 ALOGI("%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 ALOGI("%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 ALOGI("%02x", bytes[i]);
266 }
267 ALOGI("******HexDump End***********");
268 }
269
270 #ifdef __cplusplus
271 }
272 #endif /* __cplusplus */
273
274 /* Pointer to the table of LOWI callback funcs */
275 lowi_cb_table_t *LowiWifiHalApi = NULL;
276 /* LowiSupportedCapabilities read */
277 u32 lowiSupportedCapabilities = 0;
278
compareLowiVersion(u16 major,u16 minor,u16 micro)279 int compareLowiVersion(u16 major, u16 minor, u16 micro)
280 {
281 u32 currVersion = 0x10000*(WIFIHAL_LOWI_MAJOR_VERSION) + \
282 0x100*(WIFIHAL_LOWI_MINOR_VERSION) + \
283 WIFIHAL_LOWI_MICRO_VERSION;
284
285 u32 lowiVersion = 0x10000*(major) + \
286 0x100*(minor) + \
287 micro;
288
289 return (memcmp(&currVersion, &lowiVersion, sizeof(u32)));
290 }
291
292 /*
293 * This function will open the lowi shared library and obtain the
294 * Lowi Callback table and the capabilities supported.
295 * A version check is also performed in this function and if the version
296 * check fails then the callback table returned will be NULL.
297 */
fetchLowiCbTableAndCapabilities(lowi_cb_table_t ** lowi_wifihal_api,bool * lowi_get_capa_supported)298 wifi_error fetchLowiCbTableAndCapabilities(lowi_cb_table_t **lowi_wifihal_api,
299 bool *lowi_get_capa_supported)
300 {
301 getCbTable_t* lowiCbTable = NULL;
302 int ret = 0;
303 wifi_error retVal = WIFI_SUCCESS;
304
305 *lowi_wifihal_api = NULL;
306 *lowi_get_capa_supported = false;
307
308 #if __WORDSIZE == 64
309 void* lowi_handle = dlopen("/vendor/lib64/liblowi_wifihal.so", RTLD_NOW);
310 #else
311 void* lowi_handle = dlopen("/vendor/lib/liblowi_wifihal.so", RTLD_NOW);
312 #endif
313 if (!lowi_handle) {
314 ALOGE("%s: NULL lowi_handle, err: %s", __FUNCTION__, dlerror());
315 return WIFI_ERROR_UNKNOWN;
316 }
317
318 lowiCbTable = (getCbTable_t*)dlsym(lowi_handle,
319 "lowi_wifihal_get_cb_table");
320 if (!lowiCbTable) {
321 ALOGE("%s: NULL lowi callback table", __FUNCTION__);
322 return WIFI_ERROR_UNKNOWN;
323 }
324
325 *lowi_wifihal_api = lowiCbTable();
326
327 /* First check whether lowi module implements the get_lowi_version
328 * function. All the functions in lowi module starts with
329 * "lowi_wifihal_" prefix thus the below function name.
330 */
331 if ((dlsym(lowi_handle, "lowi_wifihal_get_lowi_version") != NULL) &&
332 ((*lowi_wifihal_api)->get_lowi_version != NULL)) {
333 u16 lowiMajorVersion = WIFIHAL_LOWI_MAJOR_VERSION;
334 u16 lowiMinorVersion = WIFIHAL_LOWI_MINOR_VERSION;
335 u16 lowiMicroVersion = WIFIHAL_LOWI_MICRO_VERSION;
336 int versionCheck = -1;
337
338 ret = (*lowi_wifihal_api)->get_lowi_version(&lowiMajorVersion,
339 &lowiMinorVersion,
340 &lowiMicroVersion);
341 if (ret) {
342 ALOGI("%s: get_lowi_version returned error:%d",
343 __FUNCTION__, ret);
344 retVal = WIFI_ERROR_NOT_SUPPORTED;
345 goto cleanup;
346 }
347 ALOGI("%s: Lowi version:%d.%d.%d", __FUNCTION__,
348 lowiMajorVersion, lowiMinorVersion,
349 lowiMicroVersion);
350
351 /* Compare the version with version in wifihal_internal.h */
352 versionCheck = compareLowiVersion(lowiMajorVersion,
353 lowiMinorVersion,
354 lowiMicroVersion);
355 if (versionCheck < 0) {
356 ALOGI("%s: Version Check failed:%d", __FUNCTION__,
357 versionCheck);
358 retVal = WIFI_ERROR_NOT_SUPPORTED;
359 goto cleanup;
360 }
361 else {
362 ALOGI("%s: Version Check passed:%d", __FUNCTION__,
363 versionCheck);
364 }
365 }
366 else {
367 ALOGI("%s: lowi_wifihal_get_lowi_version not present",
368 __FUNCTION__);
369 }
370
371
372 /* Check if get_lowi_capabilities func pointer exists in
373 * the lowi lib and populate lowi_get_capa_supported
374 * All the functions in lowi modules starts with
375 * "lowi_wifihal_ prefix" thus the below function name.
376 */
377 if (dlsym(lowi_handle, "lowi_wifihal_get_lowi_capabilities") != NULL) {
378 *lowi_get_capa_supported = true;
379 }
380 else {
381 ALOGI("lowi_wifihal_get_lowi_capabilities() is not supported.");
382 *lowi_get_capa_supported = false;
383 }
384 cleanup:
385 if (retVal) {
386 *lowi_wifihal_api = NULL;
387 }
388 return retVal;
389 }
390
getLowiCallbackTable(u32 requested_lowi_capabilities)391 lowi_cb_table_t *getLowiCallbackTable(u32 requested_lowi_capabilities)
392 {
393 int ret = WIFI_SUCCESS;
394 bool lowi_get_capabilities_support = false;
395
396 if (requested_lowi_capabilities == GSCAN_SUPPORTED) {
397 ALOGV("%s: Returning Null, GSCAN not supported by lowi",
398 __FUNCTION__);
399 return NULL;
400 }
401
402 ALOGI("%s: Entry", __FUNCTION__);
403 if (LowiWifiHalApi == NULL) {
404 ALOGI("%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 ALOGI("%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 ALOGI("%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 ALOGI("%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 ALOGE("%s: requested lowi capabilities: 0x%08x is not "
440 " in supported capabilities: 0x%08x. Return NULL.",
441 __FUNCTION__, requested_lowi_capabilities,
442 lowiSupportedCapabilities);
443 return NULL;
444 }
445 ALOGI("%s: Returning valid LowiWifiHalApi instance:%p",
446 __FUNCTION__, LowiWifiHalApi);
447 return LowiWifiHalApi;
448
449 cleanup:
450 ALOGI("%s: Cleaning up Lowi due to failure. Return NULL", __FUNCTION__);
451 if (LowiWifiHalApi && LowiWifiHalApi->destroy) {
452 ret = LowiWifiHalApi->destroy();
453 }
454 LowiWifiHalApi = NULL;
455 lowiSupportedCapabilities = 0;
456 return LowiWifiHalApi;
457 }
458
459