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 
192 #ifdef __cplusplus
193 extern "C"
194 {
195 #endif /* __cplusplus */
196 
hexdump(void * buf,u16 len)197 void hexdump(void *buf, u16 len)
198 {
199     int i=0;
200     char *bytes = (char *)buf;
201 
202     if (len) {
203         ALOGV("******HexDump len:%d*********", len);
204         for (i = 0; ((i + 7) < len); i+=8) {
205             ALOGV("%02x %02x %02x %02x   %02x %02x %02x %02x",
206                 bytes[i], bytes[i+1],
207                 bytes[i+2], bytes[i+3],
208                 bytes[i+4], bytes[i+5],
209                 bytes[i+6], bytes[i+7]);
210         }
211         if ((len - i) >= 4) {
212             ALOGV("%02x %02x %02x %02x",
213                 bytes[i], bytes[i+1],
214                 bytes[i+2], bytes[i+3]);
215             i+=4;
216         }
217         for (;i < len;i++) {
218             ALOGV("%02x", bytes[i]);
219         }
220         ALOGV("******HexDump End***********");
221     } else {
222         return;
223     }
224 }
225 
226 /* Firmware sends RSSI value without noise floor.
227  * Add noise floor to the same and return absolute values.
228  */
get_rssi(u8 rssi_wo_noise_floor)229 u8 get_rssi(u8 rssi_wo_noise_floor)
230 {
231     return abs((int)rssi_wo_noise_floor - 96);
232 }
233 
234 #ifdef __cplusplus
235 }
236 #endif /* __cplusplus */
237 
238 /* Pointer to the table of LOWI callback funcs */
239 lowi_cb_table_t *LowiWifiHalApi = NULL;
240 /* LowiSupportedCapabilities read */
241 u32 lowiSupportedCapabilities = 0;
242 
compareLowiVersion(u16 major,u16 minor,u16 micro)243 int compareLowiVersion(u16 major, u16 minor, u16 micro)
244 {
245     u32 currVersion = 0x10000*(WIFIHAL_LOWI_MAJOR_VERSION) + \
246                       0x100*(WIFIHAL_LOWI_MINOR_VERSION) + \
247                       WIFIHAL_LOWI_MICRO_VERSION;
248 
249     u32 lowiVersion = 0x10000*(major) + \
250                       0x100*(minor) + \
251                       micro;
252 
253     return (memcmp(&currVersion, &lowiVersion, sizeof(u32)));
254 }
255 
256 /*
257  * This function will open the lowi shared library and obtain the
258  * Lowi Callback table and the capabilities supported.
259  * A version check is also performed in this function and if the version
260  * check fails then the callback table returned will be NULL.
261  */
fetchLowiCbTableAndCapabilities(lowi_cb_table_t ** lowi_wifihal_api,bool * lowi_get_capa_supported)262 wifi_error fetchLowiCbTableAndCapabilities(lowi_cb_table_t **lowi_wifihal_api,
263                                            bool *lowi_get_capa_supported)
264 {
265     getCbTable_t* lowiCbTable = NULL;
266     int ret = 0;
267     wifi_error retVal = WIFI_SUCCESS;
268 
269     *lowi_wifihal_api = NULL;
270     *lowi_get_capa_supported = false;
271 
272 #if __WORDSIZE == 64
273     void* lowi_handle = dlopen("/vendor/lib64/liblowi_wifihal.so", RTLD_NOW);
274 #else
275     void* lowi_handle = dlopen("/vendor/lib/liblowi_wifihal.so", RTLD_NOW);
276 #endif
277     if (!lowi_handle) {
278         ALOGE("%s: NULL lowi_handle, err: %s", __FUNCTION__, dlerror());
279         return WIFI_ERROR_UNKNOWN;
280     }
281 
282     lowiCbTable = (getCbTable_t*)dlsym(lowi_handle,
283                                        "lowi_wifihal_get_cb_table");
284     if (!lowiCbTable) {
285         ALOGE("%s: NULL lowi callback table", __FUNCTION__);
286         return WIFI_ERROR_UNKNOWN;
287     }
288 
289     *lowi_wifihal_api = lowiCbTable();
290 
291     /* First check whether lowi module implements the get_lowi_version
292      * function. All the functions in lowi module starts with
293      * "lowi_wifihal_" prefix thus the below function name.
294      */
295     if ((dlsym(lowi_handle, "lowi_wifihal_get_lowi_version") != NULL) &&
296         ((*lowi_wifihal_api)->get_lowi_version != NULL)) {
297         u16 lowiMajorVersion = WIFIHAL_LOWI_MAJOR_VERSION;
298         u16 lowiMinorVersion = WIFIHAL_LOWI_MINOR_VERSION;
299         u16 lowiMicroVersion = WIFIHAL_LOWI_MICRO_VERSION;
300         int versionCheck = -1;
301 
302         ret = (*lowi_wifihal_api)->get_lowi_version(&lowiMajorVersion,
303                                                     &lowiMinorVersion,
304                                                     &lowiMicroVersion);
305         if (ret) {
306             ALOGE("%s: get_lowi_version returned error:%d",
307                   __FUNCTION__, ret);
308             retVal = WIFI_ERROR_NOT_SUPPORTED;
309             goto cleanup;
310         }
311         ALOGV("%s: Lowi version:%d.%d.%d", __FUNCTION__,
312               lowiMajorVersion, lowiMinorVersion,
313               lowiMicroVersion);
314 
315         /* Compare the version with version in wifihal_internal.h */
316         versionCheck = compareLowiVersion(lowiMajorVersion,
317                                           lowiMinorVersion,
318                                           lowiMicroVersion);
319         if (versionCheck < 0) {
320             ALOGE("%s: Version Check failed:%d", __FUNCTION__,
321                   versionCheck);
322             retVal = WIFI_ERROR_NOT_SUPPORTED;
323             goto cleanup;
324         }
325     }
326     else {
327         ALOGV("%s: lowi_wifihal_get_lowi_version not present",
328               __FUNCTION__);
329     }
330 
331 
332     /* Check if get_lowi_capabilities func pointer exists in
333      * the lowi lib and populate lowi_get_capa_supported
334      * All the functions in lowi modules starts with
335      * "lowi_wifihal_ prefix" thus the below function name.
336      */
337     if (dlsym(lowi_handle, "lowi_wifihal_get_lowi_capabilities") != NULL) {
338         *lowi_get_capa_supported = true;
339     }
340     else {
341         ALOGV("lowi_wifihal_get_lowi_capabilities() is not supported.");
342         *lowi_get_capa_supported = false;
343     }
344 cleanup:
345     if (retVal) {
346         *lowi_wifihal_api = NULL;
347     }
348     return retVal;
349 }
350 
getLowiCallbackTable(u32 requested_lowi_capabilities)351 lowi_cb_table_t *getLowiCallbackTable(u32 requested_lowi_capabilities)
352 {
353     int ret = WIFI_SUCCESS;
354     bool lowi_get_capabilities_support = false;
355 
356     if (LowiWifiHalApi == NULL) {
357         ALOGV("%s: LowiWifiHalApi Null, Initialize Lowi",
358               __FUNCTION__);
359         ret = fetchLowiCbTableAndCapabilities(&LowiWifiHalApi,
360                                               &lowi_get_capabilities_support);
361         if (ret != WIFI_SUCCESS || LowiWifiHalApi == NULL ||
362             LowiWifiHalApi->init == NULL) {
363             ALOGE("%s: LOWI is not supported.", __FUNCTION__);
364             goto cleanup;
365         }
366         /* Initialize LOWI if it isn't up already. */
367         ret = LowiWifiHalApi->init();
368         if (ret) {
369             ALOGE("%s: failed lowi initialization. "
370                 "Returned error:%d. Exit.", __FUNCTION__, ret);
371             goto cleanup;
372         }
373         if (!lowi_get_capabilities_support ||
374             LowiWifiHalApi->get_lowi_capabilities == NULL) {
375                 ALOGV("%s: Allow rtt APIs thru LOWI to proceed even though "
376                       "get_lowi_capabilities() is not supported. Returning",
377                       __FUNCTION__);
378                 lowiSupportedCapabilities |=
379                     (ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
380                 return LowiWifiHalApi;
381         }
382         ret =
383             LowiWifiHalApi->get_lowi_capabilities(&lowiSupportedCapabilities);
384         if (ret) {
385             ALOGV("%s: failed to get lowi supported capabilities."
386                 "Returned error:%d. Exit.", __FUNCTION__, ret);
387             goto cleanup;
388         }
389     }
390 
391     if ((lowiSupportedCapabilities & requested_lowi_capabilities) == 0) {
392         return NULL;
393     }
394     return LowiWifiHalApi;
395 
396 cleanup:
397     if (LowiWifiHalApi && LowiWifiHalApi->destroy) {
398         ret = LowiWifiHalApi->destroy();
399     }
400     LowiWifiHalApi = NULL;
401     lowiSupportedCapabilities = 0;
402     return LowiWifiHalApi;
403 }
404 
mapKernelErrortoWifiHalError(int kern_err)405 wifi_error mapKernelErrortoWifiHalError(int kern_err)
406 {
407     if (kern_err >= 0)
408         return WIFI_SUCCESS;
409 
410     switch (kern_err) {
411         case -EOPNOTSUPP:
412             return WIFI_ERROR_NOT_SUPPORTED;
413         case -EAGAIN:
414             return WIFI_ERROR_NOT_AVAILABLE;
415         case -EINVAL:
416             return WIFI_ERROR_INVALID_ARGS;
417         case -ETIMEDOUT:
418             return WIFI_ERROR_TIMED_OUT;
419         case -ENOMEM:
420             return WIFI_ERROR_OUT_OF_MEMORY;
421         case -EBUSY:
422             return WIFI_ERROR_BUSY;
423         case -ENOBUFS:
424             return WIFI_ERROR_TOO_MANY_REQUESTS;
425     }
426     return WIFI_ERROR_UNKNOWN;
427 }
428