• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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