1 /* 2 * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /** 18 * DOC: This file contains definition for mandatory legacy API 19 */ 20 21 #include "qdf_str.h" 22 #include "wlan_utility.h" 23 #include <wlan_cmn.h> 24 #include "wlan_osif_priv.h" 25 #include <net/cfg80211.h> 26 #include <qdf_module.h> 27 #include <wlan_vdev_mlme_api.h> 28 29 uint32_t wlan_chan_to_freq(uint8_t chan) 30 { 31 if (chan == 0 ) 32 return 0; 33 34 if (chan < WLAN_24_GHZ_CHANNEL_14) 35 return WLAN_24_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ; 36 else if (chan == WLAN_24_GHZ_CHANNEL_14) 37 return WLAN_CHAN_14_FREQ; 38 else if (chan < WLAN_24_GHZ_CHANNEL_27) 39 /* ch 15 - ch 26 */ 40 return WLAN_CHAN_15_FREQ + 41 (chan - WLAN_24_GHZ_CHANNEL_15) * WLAN_CHAN_SPACING_20MHZ; 42 else if (chan == WLAN_5_GHZ_CHANNEL_170) 43 return WLAN_CHAN_170_FREQ; 44 else 45 return WLAN_5_GHZ_BASE_FREQ + chan * WLAN_CHAN_SPACING_5MHZ; 46 } 47 48 uint8_t wlan_freq_to_chan(uint32_t freq) 49 { 50 uint8_t chan; 51 52 if (freq == 0) 53 return 0; 54 55 if (freq > WLAN_24_GHZ_BASE_FREQ && freq < WLAN_CHAN_14_FREQ) 56 chan = ((freq - WLAN_24_GHZ_BASE_FREQ) / 57 WLAN_CHAN_SPACING_5MHZ); 58 else if (freq == WLAN_CHAN_14_FREQ) 59 chan = WLAN_24_GHZ_CHANNEL_14; 60 else if ((freq > WLAN_24_GHZ_BASE_FREQ) && 61 (freq < WLAN_5_GHZ_BASE_FREQ)) 62 chan = (((freq - WLAN_CHAN_15_FREQ) / 63 WLAN_CHAN_SPACING_20MHZ) + 64 WLAN_24_GHZ_CHANNEL_15); 65 else 66 chan = (freq - WLAN_5_GHZ_BASE_FREQ) / 67 WLAN_CHAN_SPACING_5MHZ; 68 69 return chan; 70 } 71 72 bool wlan_is_ie_valid(const uint8_t *ie, size_t ie_len) 73 { 74 uint8_t elen; 75 76 while (ie_len) { 77 if (ie_len < 2) 78 return false; 79 80 elen = ie[1]; 81 ie_len -= 2; 82 ie += 2; 83 if (elen > ie_len) 84 return false; 85 86 ie_len -= elen; 87 ie += elen; 88 } 89 90 return true; 91 } 92 93 static const uint8_t *wlan_get_ie_ptr_from_eid_n_oui(uint8_t eid, 94 const uint8_t *oui, 95 uint8_t oui_size, 96 const uint8_t *ie, 97 uint16_t ie_len) 98 { 99 int32_t left = ie_len; 100 const uint8_t *ptr = ie; 101 uint8_t elem_id, elem_len; 102 103 while (left >= 2) { 104 elem_id = ptr[0]; 105 elem_len = ptr[1]; 106 left -= 2; 107 108 if (elem_len > left) 109 return NULL; 110 111 if (eid == elem_id) { 112 /* if oui is not provide eid match is enough */ 113 if (!oui) 114 return ptr; 115 116 /* 117 * if oui is provided and oui_size is more than left 118 * bytes, then we cannot have match 119 */ 120 if (oui_size > left) 121 return NULL; 122 123 if (qdf_mem_cmp(&ptr[2], oui, oui_size) == 0) 124 return ptr; 125 } 126 127 left -= elem_len; 128 ptr += (elem_len + 2); 129 } 130 131 return NULL; 132 } 133 134 const uint8_t *wlan_get_ie_ptr_from_eid(uint8_t eid, 135 const uint8_t *ie, 136 int ie_len) 137 { 138 return wlan_get_ie_ptr_from_eid_n_oui(eid, NULL, 0, ie, ie_len); 139 } 140 141 const uint8_t *wlan_get_vendor_ie_ptr_from_oui(const uint8_t *oui, 142 uint8_t oui_size, 143 const uint8_t *ie, 144 uint16_t ie_len) 145 { 146 return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_VENDOR, 147 oui, oui_size, ie, ie_len); 148 } 149 150 const uint8_t *wlan_get_ext_ie_ptr_from_ext_id(const uint8_t *oui, 151 uint8_t oui_size, 152 const uint8_t *ie, 153 uint16_t ie_len) 154 { 155 return wlan_get_ie_ptr_from_eid_n_oui(WLAN_MAC_EID_EXT, 156 oui, oui_size, ie, ie_len); 157 } 158 159 bool wlan_is_emulation_platform(uint32_t phy_version) 160 { 161 if ((phy_version == 0xABC0) || (phy_version == 0xABC1) || 162 (phy_version == 0xABC2) || (phy_version == 0xABC3) || 163 (phy_version == 0xFFFF) || (phy_version == 0xABCD)) 164 return true; 165 166 return false; 167 } 168 169 uint32_t wlan_get_pdev_id_from_vdev_id(struct wlan_objmgr_psoc *psoc, 170 uint8_t vdev_id, 171 wlan_objmgr_ref_dbgid dbg_id) 172 { 173 struct wlan_objmgr_vdev *vdev; 174 struct wlan_objmgr_pdev *pdev = NULL; 175 uint32_t pdev_id = WLAN_INVALID_PDEV_ID; 176 177 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 178 vdev_id, dbg_id); 179 180 if (vdev) { 181 pdev = wlan_vdev_get_pdev(vdev); 182 if (pdev) 183 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 184 wlan_objmgr_vdev_release_ref(vdev, dbg_id); 185 } 186 187 return pdev_id; 188 } 189 qdf_export_symbol(wlan_get_pdev_id_from_vdev_id); 190 191 static void wlan_vdev_active(struct wlan_objmgr_pdev *pdev, void *object, 192 void *arg) 193 { 194 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; 195 uint8_t *flag = (uint8_t *)arg; 196 197 wlan_vdev_obj_lock(vdev); 198 if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS) 199 *flag = 1; 200 201 wlan_vdev_obj_unlock(vdev); 202 } 203 204 QDF_STATUS wlan_vdev_is_up(struct wlan_objmgr_vdev *vdev) 205 { 206 return wlan_vdev_allow_connect_n_tx(vdev); 207 } 208 qdf_export_symbol(wlan_vdev_is_up); 209 210 QDF_STATUS wlan_util_is_vdev_active(struct wlan_objmgr_pdev *pdev, 211 wlan_objmgr_ref_dbgid dbg_id) 212 { 213 uint8_t flag = 0; 214 215 if (!pdev) 216 return QDF_STATUS_E_INVAL; 217 218 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, wlan_vdev_active, 219 &flag, 0, dbg_id); 220 221 if (flag == 1) 222 return QDF_STATUS_SUCCESS; 223 224 return QDF_STATUS_E_INVAL; 225 } 226 227 qdf_export_symbol(wlan_util_is_vdev_active); 228 229 void wlan_util_change_map_index(unsigned long *map, uint8_t id, uint8_t set) 230 { 231 if (set) 232 qdf_set_bit(id, map); 233 else 234 qdf_clear_bit(id, map); 235 } 236 237 bool wlan_util_map_index_is_set(unsigned long *map, uint8_t id) 238 { 239 return qdf_test_bit(id, map); 240 } 241 242 static void wlan_vdev_chan_change_pending(struct wlan_objmgr_pdev *pdev, 243 void *object, void *arg) 244 { 245 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; 246 unsigned long *vdev_id_map = (unsigned long *)arg; 247 uint8_t id = 0; 248 struct wlan_objmgr_psoc *psoc; 249 250 psoc = wlan_pdev_get_psoc(pdev); 251 if (!psoc) 252 return; 253 254 wlan_vdev_obj_lock(vdev); 255 if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) { 256 id = wlan_vdev_get_id(vdev); 257 /* Invalid vdev id */ 258 if (id >= wlan_psoc_get_max_vdev_count(psoc)) { 259 wlan_vdev_obj_unlock(vdev); 260 return; 261 } 262 263 wlan_util_change_map_index(vdev_id_map, id, 1); 264 } 265 266 wlan_vdev_obj_unlock(vdev); 267 } 268 269 QDF_STATUS wlan_pdev_chan_change_pending_vdevs(struct wlan_objmgr_pdev *pdev, 270 unsigned long *vdev_id_map, 271 wlan_objmgr_ref_dbgid dbg_id) 272 { 273 if (!pdev) 274 return QDF_STATUS_E_INVAL; 275 276 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 277 wlan_vdev_chan_change_pending, 278 vdev_id_map, 0, dbg_id); 279 280 return QDF_STATUS_SUCCESS; 281 } 282 283 QDF_STATUS wlan_chan_eq(struct wlan_channel *chan1, struct wlan_channel *chan2) 284 { 285 if ((chan1->ch_ieee == chan2->ch_ieee) && 286 (chan1->ch_freq_seg2 == chan2->ch_freq_seg2)) 287 return QDF_STATUS_SUCCESS; 288 289 return QDF_STATUS_E_FAILURE; 290 } 291 292 void wlan_chan_copy(struct wlan_channel *tgt, struct wlan_channel *src) 293 { 294 qdf_mem_copy(tgt, src, sizeof(struct wlan_channel)); 295 } 296 297 struct wlan_channel *wlan_vdev_get_active_channel(struct wlan_objmgr_vdev *vdev) 298 { 299 struct wlan_channel *comp_vdev_chan = NULL; 300 301 if (wlan_vdev_chan_config_valid(vdev) == QDF_STATUS_SUCCESS) { 302 /* compare with BSS channel, when vdev is active, since desired 303 * channel gets update, if channel is triggered in another path 304 */ 305 if (wlan_vdev_mlme_is_active(vdev) == QDF_STATUS_SUCCESS) 306 comp_vdev_chan = wlan_vdev_mlme_get_bss_chan(vdev); 307 else 308 comp_vdev_chan = wlan_vdev_mlme_get_des_chan(vdev); 309 } 310 311 return comp_vdev_chan; 312 } 313 314 static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object, 315 void *arg) 316 { 317 struct wlan_objmgr_vdev *comp_vdev = (struct wlan_objmgr_vdev *)object; 318 struct wlan_vdev_ch_check_filter *ch_filter = arg; 319 struct wlan_channel vdev_chan, *chan; 320 struct wlan_channel *iter_vdev_chan; 321 322 if (ch_filter->flag) 323 return; 324 325 if (comp_vdev == ch_filter->vdev) 326 return; 327 328 wlan_vdev_obj_lock(comp_vdev); 329 chan = wlan_vdev_get_active_channel(comp_vdev); 330 if (!chan) { 331 wlan_vdev_obj_unlock(comp_vdev); 332 return; 333 } 334 wlan_chan_copy(&vdev_chan, chan); 335 wlan_vdev_obj_unlock(comp_vdev); 336 337 wlan_vdev_obj_lock(ch_filter->vdev); 338 iter_vdev_chan = wlan_vdev_mlme_get_des_chan(ch_filter->vdev); 339 if (wlan_chan_eq(&vdev_chan, iter_vdev_chan) 340 != QDF_STATUS_SUCCESS) { 341 ch_filter->flag = 1; 342 qdf_nofl_err("==> iter vdev id: %d: ieee %d, mode %d", 343 wlan_vdev_get_id(comp_vdev), 344 vdev_chan.ch_ieee, 345 vdev_chan.ch_phymode); 346 qdf_nofl_err("fl %016llx, fl-ext %08x, s1 %d, s2 %d ", 347 vdev_chan.ch_flags, vdev_chan.ch_flagext, 348 vdev_chan.ch_freq_seg1, 349 vdev_chan.ch_freq_seg2); 350 qdf_nofl_err("==> base vdev id: %d: ieee %d mode %d", 351 wlan_vdev_get_id(ch_filter->vdev), 352 iter_vdev_chan->ch_ieee, 353 iter_vdev_chan->ch_phymode); 354 qdf_nofl_err("fl %016llx, fl-ext %08x s1 %d, s2 %d", 355 iter_vdev_chan->ch_flags, 356 iter_vdev_chan->ch_flagext, 357 iter_vdev_chan->ch_freq_seg1, 358 iter_vdev_chan->ch_freq_seg2); 359 } 360 wlan_vdev_obj_unlock(ch_filter->vdev); 361 } 362 363 QDF_STATUS wlan_util_pdev_vdevs_deschan_match(struct wlan_objmgr_pdev *pdev, 364 struct wlan_objmgr_vdev *vdev, 365 wlan_objmgr_ref_dbgid dbg_id) 366 { 367 struct wlan_vdev_ch_check_filter ch_filter; 368 369 if (!pdev) 370 return QDF_STATUS_E_INVAL; 371 372 if (wlan_pdev_nif_feat_cap_get(pdev, WLAN_PDEV_F_CHAN_CONCURRENCY)) 373 return QDF_STATUS_SUCCESS; 374 375 if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) == QDF_STATUS_SUCCESS) { 376 ch_filter.flag = 0; 377 ch_filter.vdev = vdev; 378 379 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 380 wlan_pdev_chan_match, 381 &ch_filter, 0, dbg_id); 382 383 wlan_objmgr_vdev_release_ref(vdev, dbg_id); 384 385 if (ch_filter.flag == 0) 386 return QDF_STATUS_SUCCESS; 387 } 388 389 return QDF_STATUS_E_FAILURE; 390 } 391 392 static void wlan_vdev_restart_progress(struct wlan_objmgr_pdev *pdev, 393 void *object, void *arg) 394 { 395 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; 396 uint8_t *flag = (uint8_t *)arg; 397 398 wlan_vdev_obj_lock(vdev); 399 if (wlan_vdev_is_restart_progress(vdev) == QDF_STATUS_SUCCESS) 400 *flag = 1; 401 402 wlan_vdev_obj_unlock(vdev); 403 } 404 405 QDF_STATUS wlan_util_is_pdev_restart_progress(struct wlan_objmgr_pdev *pdev, 406 wlan_objmgr_ref_dbgid dbg_id) 407 { 408 uint8_t flag = 0; 409 410 if (!pdev) 411 return QDF_STATUS_E_INVAL; 412 413 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 414 wlan_vdev_restart_progress, 415 &flag, 0, dbg_id); 416 417 if (flag == 1) 418 return QDF_STATUS_SUCCESS; 419 420 return QDF_STATUS_E_INVAL; 421 } 422 423 static void wlan_vdev_scan_allowed(struct wlan_objmgr_pdev *pdev, void *object, 424 void *arg) 425 { 426 struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; 427 uint8_t *flag = (uint8_t *)arg; 428 429 wlan_vdev_obj_lock(vdev); 430 if (wlan_vdev_mlme_is_scan_allowed(vdev) != QDF_STATUS_SUCCESS) 431 *flag = 1; 432 433 wlan_vdev_obj_unlock(vdev); 434 } 435 436 QDF_STATUS wlan_util_is_pdev_scan_allowed(struct wlan_objmgr_pdev *pdev, 437 wlan_objmgr_ref_dbgid dbg_id) 438 { 439 uint8_t flag = 0; 440 441 if (!pdev) 442 return QDF_STATUS_E_INVAL; 443 444 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 445 wlan_vdev_scan_allowed, 446 &flag, 0, dbg_id); 447 448 if (flag == 1) 449 return QDF_STATUS_E_FAILURE; 450 451 return QDF_STATUS_SUCCESS; 452 } 453 454 void 455 wlan_util_stats_get_rssi(bool db2dbm_enabled, int32_t bcn_snr, int32_t dat_snr, 456 int8_t *rssi) 457 { 458 uint32_t snr; 459 460 if (db2dbm_enabled) { 461 if (TGT_IS_VALID_RSSI(bcn_snr)) 462 *rssi = bcn_snr; 463 else if (TGT_IS_VALID_RSSI(dat_snr)) 464 *rssi = dat_snr; 465 else 466 *rssi = TGT_NOISE_FLOOR_DBM; 467 } else { 468 if (TGT_IS_VALID_SNR(bcn_snr)) 469 snr = bcn_snr; 470 else if (TGT_IS_VALID_SNR(dat_snr)) 471 snr = dat_snr; 472 else 473 snr = TGT_INVALID_SNR; 474 475 /* Get the absolute rssi value from the current rssi value */ 476 *rssi = snr + TGT_NOISE_FLOOR_DBM; 477 } 478 } 479 480 /** 481 * wlan_util_get_mode_specific_peer_count - This api gives vdev mode specific 482 * peer count` 483 * @pdev: PDEV object 484 * @object: vdev object 485 * @arg: argument passed by caller 486 * 487 * Return: void 488 */ 489 static void 490 wlan_util_get_mode_specific_peer_count(struct wlan_objmgr_pdev *pdev, 491 void *object, void *arg) 492 { 493 struct wlan_objmgr_vdev *vdev = object; 494 uint16_t temp_count = 0; 495 struct wlan_op_mode_peer_count *count = arg; 496 497 wlan_vdev_obj_lock(vdev); 498 if (wlan_vdev_mlme_get_opmode(vdev) == count->opmode) { 499 temp_count = wlan_vdev_get_peer_count(vdev); 500 /* Decrement the self peer count */ 501 if (temp_count > 1) 502 count->peer_count += (temp_count - 1); 503 } 504 wlan_vdev_obj_unlock(vdev); 505 } 506 507 uint16_t wlan_util_get_peer_count_for_mode(struct wlan_objmgr_pdev *pdev, 508 enum QDF_OPMODE mode) 509 { 510 struct wlan_op_mode_peer_count count; 511 512 count.opmode = mode; 513 count.peer_count = 0; 514 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 515 wlan_util_get_mode_specific_peer_count, &count, 516 0, WLAN_OBJMGR_ID); 517 518 return count.peer_count; 519 } 520 521