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 
     24 #include "wifi_hal.h"
     25 #include "common.h"
     26 
     27 interface_info *getIfaceInfo(wifi_interface_handle handle)
     28 {
     29     return (interface_info *)handle;
     30 }
     31 
     32 wifi_handle getWifiHandle(wifi_interface_handle handle)
     33 {
     34     return getIfaceInfo(handle)->handle;
     35 }
     36 
     37 hal_info *getHalInfo(wifi_handle handle)
     38 {
     39     return (hal_info *)handle;
     40 }
     41 
     42 hal_info *getHalInfo(wifi_interface_handle handle)
     43 {
     44     return getHalInfo(getWifiHandle(handle));
     45 }
     46 
     47 wifi_handle getWifiHandle(hal_info *info)
     48 {
     49     return (wifi_handle)info;
     50 }
     51 
     52 wifi_interface_handle getIfaceHandle(interface_info *info)
     53 {
     54     return (wifi_interface_handle)info;
     55 }
     56 
     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             ALOGV("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         ALOGV("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 
     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             ALOGV("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         ALOGV("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 
    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             ALOGV("Successfully removed event handler for command %d", cmd);
    155             break;
    156         }
    157     }
    158 
    159     pthread_mutex_unlock(&info->cb_lock);
    160 }
    161 
    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             ALOGV("Successfully removed event handler for vendor 0x%0x", id);
    182             break;
    183         }
    184     }
    185 
    186     pthread_mutex_unlock(&info->cb_lock);
    187 }
    188 
    189 
    190 wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
    191 {
    192     hal_info *info = (hal_info *)handle;
    193 
    194     if (info->num_cmd < info->alloc_cmd) {
    195         info->cmd[info->num_cmd].id   = id;
    196         info->cmd[info->num_cmd].cmd  = cmd;
    197         info->num_cmd++;
    198         ALOGV("Successfully added command %d: %p", id, cmd);
    199         return WIFI_SUCCESS;
    200     } else {
    201         return WIFI_ERROR_OUT_OF_MEMORY;
    202     }
    203 }
    204 
    205 WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
    206 {
    207     hal_info *info = (hal_info *)handle;
    208 
    209     for (int i = 0; i < info->num_cmd; i++) {
    210         if (info->cmd[i].id == id) {
    211             WifiCommand *cmd = info->cmd[i].cmd;
    212             memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
    213             info->num_cmd--;
    214             ALOGV("Successfully removed command %d: %p", id, cmd);
    215             return cmd;
    216         }
    217     }
    218 
    219     return NULL;
    220 }
    221 
    222 void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
    223 {
    224     hal_info *info = (hal_info *)handle;
    225 
    226     for (int i = 0; i < info->num_cmd; i++) {
    227         if (info->cmd[i].cmd == cmd) {
    228             int id = info->cmd[i].id;
    229             memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
    230             info->num_cmd--;
    231             ALOGV("Successfully removed command %d: %p", id, cmd);
    232             return;
    233         }
    234     }
    235 }
    236 
    237 #ifdef __cplusplus
    238 extern "C"
    239 {
    240 #endif /* __cplusplus */
    241 
    242 void hexdump(void *buf, u16 len)
    243 {
    244     int i=0;
    245     char *bytes = (char *)buf;
    246 
    247     if (len) {
    248         ALOGV("******HexDump len:%d*********", len);
    249         for (i = 0; ((i + 7) < len); i+=8) {
    250             ALOGV("%02x %02x %02x %02x   %02x %02x %02x %02x",
    251                 bytes[i], bytes[i+1],
    252                 bytes[i+2], bytes[i+3],
    253                 bytes[i+4], bytes[i+5],
    254                 bytes[i+6], bytes[i+7]);
    255         }
    256         if ((len - i) >= 4) {
    257             ALOGV("%02x %02x %02x %02x",
    258                 bytes[i], bytes[i+1],
    259                 bytes[i+2], bytes[i+3]);
    260             i+=4;
    261         }
    262         for (;i < len;i++) {
    263             ALOGV("%02x", bytes[i]);
    264         }
    265         ALOGV("******HexDump End***********");
    266     } else {
    267         return;
    268     }
    269 }
    270 
    271 /* Firmware sends RSSI value without noise floor.
    272  * Add noise floor to the same and return absolute values.
    273  */
    274 u8 get_rssi(u8 rssi_wo_noise_floor)
    275 {
    276     return abs((int)rssi_wo_noise_floor - 96);
    277 }
    278 
    279 #ifdef __cplusplus
    280 }
    281 #endif /* __cplusplus */
    282 
    283 /* Pointer to the table of LOWI callback funcs */
    284 lowi_cb_table_t *LowiWifiHalApi = NULL;
    285 /* LowiSupportedCapabilities read */
    286 u32 lowiSupportedCapabilities = 0;
    287 
    288 int compareLowiVersion(u16 major, u16 minor, u16 micro)
    289 {
    290     u32 currVersion = 0x10000*(WIFIHAL_LOWI_MAJOR_VERSION) + \
    291                       0x100*(WIFIHAL_LOWI_MINOR_VERSION) + \
    292                       WIFIHAL_LOWI_MICRO_VERSION;
    293 
    294     u32 lowiVersion = 0x10000*(major) + \
    295                       0x100*(minor) + \
    296                       micro;
    297 
    298     return (memcmp(&currVersion, &lowiVersion, sizeof(u32)));
    299 }
    300 
    301 /*
    302  * This function will open the lowi shared library and obtain the
    303  * Lowi Callback table and the capabilities supported.
    304  * A version check is also performed in this function and if the version
    305  * check fails then the callback table returned will be NULL.
    306  */
    307 wifi_error fetchLowiCbTableAndCapabilities(lowi_cb_table_t **lowi_wifihal_api,
    308                                            bool *lowi_get_capa_supported)
    309 {
    310     getCbTable_t* lowiCbTable = NULL;
    311     int ret = 0;
    312     wifi_error retVal = WIFI_SUCCESS;
    313 
    314     *lowi_wifihal_api = NULL;
    315     *lowi_get_capa_supported = false;
    316 
    317 #if __WORDSIZE == 64
    318     void* lowi_handle = dlopen("/vendor/lib64/liblowi_wifihal.so", RTLD_NOW);
    319 #else
    320     void* lowi_handle = dlopen("/vendor/lib/liblowi_wifihal.so", RTLD_NOW);
    321 #endif
    322     if (!lowi_handle) {
    323         ALOGE("%s: NULL lowi_handle, err: %s", __FUNCTION__, dlerror());
    324         return WIFI_ERROR_UNKNOWN;
    325     }
    326 
    327     lowiCbTable = (getCbTable_t*)dlsym(lowi_handle,
    328                                        "lowi_wifihal_get_cb_table");
    329     if (!lowiCbTable) {
    330         ALOGE("%s: NULL lowi callback table", __FUNCTION__);
    331         return WIFI_ERROR_UNKNOWN;
    332     }
    333 
    334     *lowi_wifihal_api = lowiCbTable();
    335 
    336     /* First check whether lowi module implements the get_lowi_version
    337      * function. All the functions in lowi module starts with
    338      * "lowi_wifihal_" prefix thus the below function name.
    339      */
    340     if ((dlsym(lowi_handle, "lowi_wifihal_get_lowi_version") != NULL) &&
    341         ((*lowi_wifihal_api)->get_lowi_version != NULL)) {
    342         u16 lowiMajorVersion = WIFIHAL_LOWI_MAJOR_VERSION;
    343         u16 lowiMinorVersion = WIFIHAL_LOWI_MINOR_VERSION;
    344         u16 lowiMicroVersion = WIFIHAL_LOWI_MICRO_VERSION;
    345         int versionCheck = -1;
    346 
    347         ret = (*lowi_wifihal_api)->get_lowi_version(&lowiMajorVersion,
    348                                                     &lowiMinorVersion,
    349                                                     &lowiMicroVersion);
    350         if (ret) {
    351             ALOGE("%s: get_lowi_version returned error:%d",
    352                   __FUNCTION__, ret);
    353             retVal = WIFI_ERROR_NOT_SUPPORTED;
    354             goto cleanup;
    355         }
    356         ALOGV("%s: Lowi version:%d.%d.%d", __FUNCTION__,
    357               lowiMajorVersion, lowiMinorVersion,
    358               lowiMicroVersion);
    359 
    360         /* Compare the version with version in wifihal_internal.h */
    361         versionCheck = compareLowiVersion(lowiMajorVersion,
    362                                           lowiMinorVersion,
    363                                           lowiMicroVersion);
    364         if (versionCheck < 0) {
    365             ALOGE("%s: Version Check failed:%d", __FUNCTION__,
    366                   versionCheck);
    367             retVal = WIFI_ERROR_NOT_SUPPORTED;
    368             goto cleanup;
    369         }
    370     }
    371     else {
    372         ALOGV("%s: lowi_wifihal_get_lowi_version not present",
    373               __FUNCTION__);
    374     }
    375 
    376 
    377     /* Check if get_lowi_capabilities func pointer exists in
    378      * the lowi lib and populate lowi_get_capa_supported
    379      * All the functions in lowi modules starts with
    380      * "lowi_wifihal_ prefix" thus the below function name.
    381      */
    382     if (dlsym(lowi_handle, "lowi_wifihal_get_lowi_capabilities") != NULL) {
    383         *lowi_get_capa_supported = true;
    384     }
    385     else {
    386         ALOGV("lowi_wifihal_get_lowi_capabilities() is not supported.");
    387         *lowi_get_capa_supported = false;
    388     }
    389 cleanup:
    390     if (retVal) {
    391         *lowi_wifihal_api = NULL;
    392     }
    393     return retVal;
    394 }
    395 
    396 lowi_cb_table_t *getLowiCallbackTable(u32 requested_lowi_capabilities)
    397 {
    398     int ret = WIFI_SUCCESS;
    399     bool lowi_get_capabilities_support = false;
    400 
    401     if (LowiWifiHalApi == NULL) {
    402         ALOGV("%s: LowiWifiHalApi Null, Initialize Lowi",
    403               __FUNCTION__);
    404         ret = fetchLowiCbTableAndCapabilities(&LowiWifiHalApi,
    405                                               &lowi_get_capabilities_support);
    406         if (ret != WIFI_SUCCESS || LowiWifiHalApi == NULL ||
    407             LowiWifiHalApi->init == NULL) {
    408             ALOGE("%s: LOWI is not supported.", __FUNCTION__);
    409             goto cleanup;
    410         }
    411         /* Initialize LOWI if it isn't up already. */
    412         ret = LowiWifiHalApi->init();
    413         if (ret) {
    414             ALOGE("%s: failed lowi initialization. "
    415                 "Returned error:%d. Exit.", __FUNCTION__, ret);
    416             goto cleanup;
    417         }
    418         if (!lowi_get_capabilities_support ||
    419             LowiWifiHalApi->get_lowi_capabilities == NULL) {
    420                 ALOGV("%s: Allow rtt APIs thru LOWI to proceed even though "
    421                       "get_lowi_capabilities() is not supported. Returning",
    422                       __FUNCTION__);
    423                 lowiSupportedCapabilities |=
    424                     (ONE_SIDED_RANGING_SUPPORTED|DUAL_SIDED_RANGING_SUPPORED);
    425                 return LowiWifiHalApi;
    426         }
    427         ret =
    428             LowiWifiHalApi->get_lowi_capabilities(&lowiSupportedCapabilities);
    429         if (ret) {
    430             ALOGV("%s: failed to get lowi supported capabilities."
    431                 "Returned error:%d. Exit.", __FUNCTION__, ret);
    432             goto cleanup;
    433         }
    434     }
    435 
    436     if ((lowiSupportedCapabilities & requested_lowi_capabilities) == 0) {
    437         return NULL;
    438     }
    439     return LowiWifiHalApi;
    440 
    441 cleanup:
    442     if (LowiWifiHalApi && LowiWifiHalApi->destroy) {
    443         ret = LowiWifiHalApi->destroy();
    444     }
    445     LowiWifiHalApi = NULL;
    446     lowiSupportedCapabilities = 0;
    447     return LowiWifiHalApi;
    448 }
    449 
    450