Home | History | Annotate | Download | only in wifi_hal
      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 
     29 interface_info *getIfaceInfo(wifi_interface_handle handle)
     30 {
     31     return (interface_info *)handle;
     32 }
     33 
     34 wifi_handle getWifiHandle(wifi_interface_handle handle)
     35 {
     36     return getIfaceInfo(handle)->handle;
     37 }
     38 
     39 hal_info *getHalInfo(wifi_handle handle)
     40 {
     41     return (hal_info *)handle;
     42 }
     43 
     44 hal_info *getHalInfo(wifi_interface_handle handle)
     45 {
     46     return getHalInfo(getWifiHandle(handle));
     47 }
     48 
     49 wifi_handle getWifiHandle(hal_info *info)
     50 {
     51     return (wifi_handle)info;
     52 }
     53 
     54 wifi_interface_handle getIfaceHandle(interface_info *info)
     55 {
     56     return (wifi_interface_handle)info;
     57 }
     58 
     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 
     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 
    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 
    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 
    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  */
    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 
    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  */
    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 
    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 
    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     }
    424     return WIFI_ERROR_UNKNOWN;
    425 }
    426