• 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-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