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 29interface_info *getIfaceInfo(wifi_interface_handle handle) 30{ 31 return (interface_info *)handle; 32} 33 34wifi_handle getWifiHandle(wifi_interface_handle handle) 35{ 36 return getIfaceInfo(handle)->handle; 37} 38 39hal_info *getHalInfo(wifi_handle handle) 40{ 41 return (hal_info *)handle; 42} 43 44hal_info *getHalInfo(wifi_interface_handle handle) 45{ 46 return getHalInfo(getWifiHandle(handle)); 47} 48 49wifi_handle getWifiHandle(hal_info *info) 50{ 51 return (wifi_handle)info; 52} 53 54wifi_interface_handle getIfaceHandle(interface_info *info) 55{ 56 return (wifi_interface_handle)info; 57} 58 59wifi_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 95wifi_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 135void 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 164void 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 193extern "C" 194{ 195#endif /* __cplusplus */ 196 197void 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 */ 229u8 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 */ 239lowi_cb_table_t *LowiWifiHalApi = NULL; 240/* LowiSupportedCapabilities read */ 241u32 lowiSupportedCapabilities = 0; 242 243int 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 */ 262wifi_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 } 344cleanup: 345 if (retVal) { 346 *lowi_wifihal_api = NULL; 347 } 348 return retVal; 349} 350 351lowi_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 396cleanup: 397 if (LowiWifiHalApi && LowiWifiHalApi->destroy) { 398 ret = LowiWifiHalApi->destroy(); 399 } 400 LowiWifiHalApi = NULL; 401 lowiSupportedCapabilities = 0; 402 return LowiWifiHalApi; 403} 404 405wifi_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