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-types.h> 21 #include <dlfcn.h> 22 23 #include "wifi_hal.h" 24 #include "common.h" 25 #include <netlink-types.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