1 /* 2 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. 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: contains EPCS (Emergency Preparedness Communications Service) 19 * related functionality 20 */ 21 #include <wlan_cmn.h> 22 #include <wlan_cm_public_struct.h> 23 #include "wlan_epcs_api.h" 24 #include <wlan_mlo_epcs.h> 25 #include "wlan_cm_api.h" 26 #include "wlan_mlo_mgr_roam.h" 27 #include "wlan_cmn_ieee80211.h" 28 #include "dot11f.h" 29 30 #define EPCS_MIN_DIALOG_TOKEN 1 31 #define EPCS_MAX_DIALOG_TOKEN 0xFF 32 33 static struct ac_param_record default_epcs_edca[] = { 34 #ifndef ANI_LITTLE_BIT_ENDIAN 35 /* The txop is multiple of 32us units */ 36 {0x07, 0x95, 79 /* 2.528ms */}, 37 {0x03, 0x95, 79 /* 2.528ms */}, 38 {0x02, 0x54, 128 /* 4.096ms */}, 39 {0x02, 0x43, 65 /* 2.080ms */} 40 #else 41 {0x70, 0x59, 79 /* 2.528ms */}, 42 {0x30, 0x59, 79 /* 2.528ms */}, 43 {0x20, 0x45, 128 /* 4.096ms */}, 44 {0x20, 0x34, 65 /* 2.080ms */} 45 #endif 46 }; 47 48 static 49 const char *epcs_get_event_str(enum wlan_epcs_evt event) 50 { 51 if (event > WLAN_EPCS_EV_ACTION_FRAME_MAX) 52 return ""; 53 54 switch (event) { 55 CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_REQ); 56 CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_RESP); 57 CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_REQ); 58 CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_RESP); 59 CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN); 60 CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN); 61 default: 62 return "Unknown"; 63 } 64 } 65 66 static uint8_t 67 epcs_gen_dialog_token(struct wlan_mlo_peer_epcs_info *epcs_info) 68 { 69 if (!epcs_info) 70 return 0; 71 72 if (epcs_info->self_gen_dialog_token == EPCS_MAX_DIALOG_TOKEN) 73 /* wrap is ok */ 74 epcs_info->self_gen_dialog_token = EPCS_MIN_DIALOG_TOKEN; 75 else 76 epcs_info->self_gen_dialog_token += 1; 77 78 mlme_debug("gen dialog token %d", epcs_info->self_gen_dialog_token); 79 return epcs_info->self_gen_dialog_token; 80 } 81 82 static void epcs_update_ac_value(tSirMacEdcaParamRecord *edca, 83 struct ac_param_record *epcs) 84 { 85 edca->aci.rsvd = epcs->aci_aifsn >> RSVD_SHIFT_BIT & RSVD_MASK; 86 edca->aci.aci = epcs->aci_aifsn >> ACI_SHIFT_BIT & ACI_MASK; 87 edca->aci.acm = epcs->aci_aifsn >> ACM_SHIFT_BIT & ACM_MASK; 88 edca->aci.aifsn = epcs->aci_aifsn >> AIFSN_SHIFT_BIT & AIFSN_MASK; 89 90 edca->cw.max = epcs->ecw_min_max >> CWMAX_SHIFT_BIT & CWMAX_MASK; 91 edca->cw.min = epcs->ecw_min_max >> CWMIN_SHIFT_BIT & CWMIN_MASK; 92 93 edca->txoplimit = epcs->txop_limit; 94 mlme_debug("edca rsvd %d, aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", 95 edca->aci.rsvd, edca->aci.aci, edca->aci.acm, 96 edca->aci.aifsn, edca->cw.max, edca->cw.min); 97 } 98 99 static void epcs_update_mu_ac_value(tSirMacEdcaParamRecord *edca, 100 struct muac_param_record *epcs) 101 { 102 edca->aci.rsvd = epcs->aci_aifsn >> RSVD_SHIFT_BIT & RSVD_MASK; 103 edca->aci.aci = epcs->aci_aifsn >> ACI_SHIFT_BIT & ACI_MASK; 104 edca->aci.acm = epcs->aci_aifsn >> ACM_SHIFT_BIT & ACM_MASK; 105 edca->aci.aifsn = epcs->aci_aifsn >> AIFSN_SHIFT_BIT & AIFSN_MASK; 106 107 edca->cw.max = epcs->ecw_min_max >> CWMAX_SHIFT_BIT & CWMAX_MASK; 108 edca->cw.min = epcs->ecw_min_max >> CWMIN_SHIFT_BIT & CWMIN_MASK; 109 110 edca->txoplimit = epcs->mu_edca_timer; 111 mlme_debug("muac rsvd %d, aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", 112 edca->aci.rsvd, edca->aci.aci, edca->aci.acm, 113 edca->aci.aifsn, edca->cw.max, edca->cw.min); 114 } 115 116 static QDF_STATUS 117 epcs_update_def_edca_param(struct wlan_objmgr_vdev *vdev) 118 { 119 int i; 120 struct mac_context *mac_ctx; 121 tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0}; 122 123 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 124 if (!mac_ctx) 125 return QDF_STATUS_E_INVAL; 126 127 for (i = 0; i < QCA_WLAN_AC_ALL; i++) { 128 epcs_update_ac_value(&edca[i], &default_epcs_edca[i]); 129 edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i]; 130 } 131 132 mlme_debug("using default edca info"); 133 return lim_send_epcs_update_edca_params(vdev, edca, false); 134 } 135 136 static QDF_STATUS 137 epcs_update_edca_param(struct wlan_objmgr_vdev *vdev, 138 struct edca_ie *edca_ie) 139 { 140 struct mac_context *mac_ctx; 141 struct ac_param_record *ac_record; 142 tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0}; 143 int i; 144 145 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 146 if (!mac_ctx) 147 return QDF_STATUS_E_INVAL; 148 149 if (edca_ie->ie != DOT11F_EID_EDCAPARAMSET || 150 edca_ie->len != DOT11F_IE_EDCAPARAMSET_MIN_LEN) { 151 mlme_debug("edca info is not valid or not exist"); 152 return QDF_STATUS_E_INVAL; 153 } 154 155 ac_record = edca_ie->ac_record; 156 for (i = 0; i < QCA_WLAN_AC_ALL; i++) { 157 epcs_update_ac_value(&edca[i], &ac_record[i]); 158 edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i]; 159 } 160 161 return lim_send_epcs_update_edca_params(vdev, edca, false); 162 } 163 164 static QDF_STATUS 165 epcs_update_ven_wmm_param(struct wlan_objmgr_vdev *vdev, uint8_t *ven_wme_ie) 166 { 167 struct mac_context *mac_ctx; 168 tDot11fIEWMMParams wmm_para = {0}; 169 tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0}; 170 uint32_t status; 171 172 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 173 if (!mac_ctx) 174 return QDF_STATUS_E_INVAL; 175 176 status = dot11f_unpack_ie_wmm_params(mac_ctx, 177 ven_wme_ie + WMM_VENDOR_HEADER_LEN, 178 DOT11F_IE_WMMPARAMS_MIN_LEN, 179 &wmm_para, false); 180 if (status != DOT11F_PARSE_SUCCESS) { 181 mlme_debug("EPCS parsing wmm ie error"); 182 return QDF_STATUS_E_INVAL; 183 } 184 185 edca[QCA_WLAN_AC_BE].aci.rsvd = wmm_para.unused1; 186 edca[QCA_WLAN_AC_BE].aci.aci = wmm_para.acbe_aci; 187 edca[QCA_WLAN_AC_BE].aci.acm = wmm_para.acbe_acm; 188 edca[QCA_WLAN_AC_BE].aci.aifsn = wmm_para.acbe_aifsn; 189 edca[QCA_WLAN_AC_BE].cw.max = wmm_para.acbe_acwmax; 190 edca[QCA_WLAN_AC_BE].cw.min = wmm_para.acbe_acwmin; 191 edca[QCA_WLAN_AC_BE].txoplimit = wmm_para.acbe_txoplimit; 192 edca[QCA_WLAN_AC_BE].no_ack = 193 mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BE]; 194 mlme_debug("WMM BE aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", 195 edca[QCA_WLAN_AC_BE].aci.aci, 196 edca[QCA_WLAN_AC_BE].aci.acm, 197 edca[QCA_WLAN_AC_BE].aci.aifsn, 198 edca[QCA_WLAN_AC_BE].cw.max, 199 edca[QCA_WLAN_AC_BE].cw.min); 200 201 edca[QCA_WLAN_AC_BK].aci.rsvd = wmm_para.unused2; 202 edca[QCA_WLAN_AC_BK].aci.aci = wmm_para.acbk_aci; 203 edca[QCA_WLAN_AC_BK].aci.acm = wmm_para.acbk_acm; 204 edca[QCA_WLAN_AC_BK].aci.aifsn = wmm_para.acbk_aifsn; 205 edca[QCA_WLAN_AC_BK].cw.max = wmm_para.acbk_acwmax; 206 edca[QCA_WLAN_AC_BK].cw.min = wmm_para.acbk_acwmin; 207 edca[QCA_WLAN_AC_BK].txoplimit = wmm_para.acbk_txoplimit; 208 edca[QCA_WLAN_AC_BK].no_ack = 209 mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BK]; 210 mlme_debug("WMM BK aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", 211 edca[QCA_WLAN_AC_BK].aci.aci, 212 edca[QCA_WLAN_AC_BK].aci.acm, 213 edca[QCA_WLAN_AC_BK].aci.aifsn, 214 edca[QCA_WLAN_AC_BK].cw.max, 215 edca[QCA_WLAN_AC_BK].cw.min); 216 217 edca[QCA_WLAN_AC_VI].aci.rsvd = wmm_para.unused3; 218 edca[QCA_WLAN_AC_VI].aci.aci = wmm_para.acvi_aci; 219 edca[QCA_WLAN_AC_VI].aci.acm = wmm_para.acvi_acm; 220 edca[QCA_WLAN_AC_VI].aci.aifsn = wmm_para.acvi_aifsn; 221 edca[QCA_WLAN_AC_VI].cw.max = wmm_para.acvi_acwmax; 222 edca[QCA_WLAN_AC_VI].cw.min = wmm_para.acvi_acwmin; 223 edca[QCA_WLAN_AC_VI].txoplimit = wmm_para.acvi_txoplimit; 224 edca[QCA_WLAN_AC_VI].no_ack = 225 mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VI]; 226 mlme_debug("WMM VI aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", 227 edca[QCA_WLAN_AC_VI].aci.aci, 228 edca[QCA_WLAN_AC_VI].aci.acm, 229 edca[QCA_WLAN_AC_VI].aci.aifsn, 230 edca[QCA_WLAN_AC_VI].cw.max, 231 edca[QCA_WLAN_AC_VI].cw.min); 232 233 edca[QCA_WLAN_AC_VO].aci.rsvd = wmm_para.unused4; 234 edca[QCA_WLAN_AC_VO].aci.aci = wmm_para.acvo_aci; 235 edca[QCA_WLAN_AC_VO].aci.acm = wmm_para.acvo_acm; 236 edca[QCA_WLAN_AC_VO].aci.aifsn = wmm_para.acvo_aifsn; 237 edca[QCA_WLAN_AC_VO].cw.max = wmm_para.acvo_acwmax; 238 edca[QCA_WLAN_AC_VO].cw.min = wmm_para.acvo_acwmin; 239 edca[QCA_WLAN_AC_VO].txoplimit = wmm_para.acvo_txoplimit; 240 edca[QCA_WLAN_AC_VO].no_ack = 241 mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VO]; 242 mlme_debug("WMM VO aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", 243 edca[QCA_WLAN_AC_VO].aci.aci, 244 edca[QCA_WLAN_AC_VO].aci.acm, 245 edca[QCA_WLAN_AC_VO].aci.aifsn, 246 edca[QCA_WLAN_AC_VO].cw.max, 247 edca[QCA_WLAN_AC_VO].cw.min); 248 249 return lim_send_epcs_update_edca_params(vdev, edca, false); 250 } 251 252 static QDF_STATUS 253 epcs_update_mu_edca_param(struct wlan_objmgr_vdev *vdev, 254 struct muedca_ie *muedca) 255 { 256 struct mac_context *mac_ctx; 257 struct muac_param_record *mu_record; 258 tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0}; 259 int i; 260 261 if (muedca->elem_id != DOT11F_EID_MU_EDCA_PARAM_SET || 262 muedca->elem_len != (DOT11F_IE_MU_EDCA_PARAM_SET_MIN_LEN + 1)) { 263 mlme_debug("mu edca info for epcs is not valid or not exist"); 264 return QDF_STATUS_SUCCESS; 265 } 266 267 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 268 if (!mac_ctx) 269 return QDF_STATUS_E_INVAL; 270 271 mu_record = muedca->mu_record; 272 for (i = 0; i < QCA_WLAN_AC_ALL; i++) { 273 epcs_update_mu_ac_value(&edca[i], &mu_record[i]); 274 edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i]; 275 } 276 277 return lim_send_epcs_update_edca_params(vdev, edca, true); 278 } 279 280 static QDF_STATUS 281 epcs_restore_edca_param(struct wlan_objmgr_vdev *vdev) 282 { 283 struct wlan_objmgr_vdev *link_vdev; 284 struct wlan_mlo_dev_context *mlo_dev_ctx; 285 int i; 286 287 if (!vdev) 288 return QDF_STATUS_E_INVAL; 289 290 mlo_dev_ctx = vdev->mlo_dev_ctx; 291 if (!mlo_dev_ctx) 292 return QDF_STATUS_E_INVAL; 293 294 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 295 link_vdev = mlo_dev_ctx->wlan_vdev_list[i]; 296 if (!link_vdev) 297 continue; 298 lim_send_epcs_restore_edca_params(link_vdev); 299 } 300 301 return QDF_STATUS_SUCCESS; 302 } 303 304 static QDF_STATUS epcs_handle_rx_req(struct wlan_objmgr_vdev *vdev, 305 struct wlan_objmgr_peer *peer, 306 void *event_data, uint32_t len) 307 { 308 struct wlan_mlo_peer_context *ml_peer; 309 struct wlan_mlo_peer_epcs_info *epcs_info; 310 struct wlan_epcs_info epcs_req = {0}; 311 struct wlan_action_frame_args args; 312 struct ml_pa_info *edca_info; 313 struct ml_pa_partner_link_info *link; 314 struct wlan_objmgr_vdev *link_vdev; 315 uint32_t i; 316 QDF_STATUS status; 317 318 if (!vdev || !peer) 319 return QDF_STATUS_E_INVAL; 320 321 ml_peer = peer->mlo_peer_ctx; 322 if (!ml_peer) 323 return QDF_STATUS_E_FAILURE; 324 325 epcs_info = &ml_peer->epcs_info; 326 if (epcs_info->state == EPCS_ENABLE) { 327 mlme_err("EPCS has been enable, ignore the req."); 328 return QDF_STATUS_E_ALREADY; 329 } 330 331 status = wlan_mlo_parse_epcs_action_frame(&epcs_req, event_data, len); 332 if (status != QDF_STATUS_SUCCESS) { 333 mlme_err("Unable to parse EPCS request action frame"); 334 return QDF_STATUS_E_FAILURE; 335 } 336 337 epcs_info->self_gen_dialog_token = epcs_req.dialog_token; 338 edca_info = &epcs_req.pa_info; 339 for (i = 0; i < edca_info->num_links; i++) { 340 link = &edca_info->link_info[i]; 341 link_vdev = mlo_get_vdev_by_link_id(vdev, link->link_id, 342 WLAN_MLO_MGR_ID); 343 if (!link_vdev) 344 continue; 345 346 if (link->edca_ie_present) 347 epcs_update_edca_param(link_vdev, &link->edca); 348 else if (link->ven_wme_ie_present) 349 epcs_update_ven_wmm_param(link_vdev, 350 &link->ven_wme_ie_bytes[0]); 351 else 352 epcs_update_def_edca_param(link_vdev); 353 354 if (link->muedca_ie_present) 355 epcs_update_mu_edca_param(link_vdev, &link->muedca); 356 357 wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLO_MGR_ID); 358 } 359 360 args.category = ACTION_CATEGORY_PROTECTED_EHT; 361 args.action = EHT_EPCS_RESPONSE; 362 args.arg1 = epcs_info->self_gen_dialog_token; 363 args.arg2 = QDF_STATUS_SUCCESS; 364 365 status = lim_send_epcs_action_rsp_frame(vdev, 366 wlan_peer_get_macaddr(peer), 367 &args); 368 if (status != QDF_STATUS_SUCCESS) { 369 mlme_err("Send EPCS response frame error"); 370 epcs_restore_edca_param(vdev); 371 } else { 372 epcs_info->state = EPCS_ENABLE; 373 mlme_debug("EPCS (responder) state: Teardown -> Enable"); 374 } 375 376 return status; 377 } 378 379 static QDF_STATUS epcs_handle_rx_resp(struct wlan_objmgr_vdev *vdev, 380 struct wlan_objmgr_peer *peer, 381 void *event_data, uint32_t len) 382 { 383 struct wlan_mlo_peer_context *ml_peer; 384 struct wlan_mlo_peer_epcs_info *epcs_info; 385 struct wlan_epcs_info epcs_rsp = {0}; 386 struct ml_pa_info *edca_info; 387 struct ml_pa_partner_link_info *link; 388 struct wlan_objmgr_vdev *link_vdev; 389 uint32_t i; 390 QDF_STATUS status; 391 392 if (!vdev || !peer) 393 return QDF_STATUS_E_NULL_VALUE; 394 395 ml_peer = peer->mlo_peer_ctx; 396 if (!ml_peer) 397 return QDF_STATUS_E_NULL_VALUE; 398 399 epcs_info = &ml_peer->epcs_info; 400 if (epcs_info->state == EPCS_ENABLE) { 401 mlme_err("EPCS has been enable, ignore the rsp."); 402 return QDF_STATUS_E_ALREADY; 403 } 404 405 status = wlan_mlo_parse_epcs_action_frame(&epcs_rsp, event_data, len); 406 if (status != QDF_STATUS_SUCCESS) { 407 mlme_err("Unable to parse EPCS response action frame"); 408 return QDF_STATUS_E_FAILURE; 409 } 410 411 if (epcs_info->self_gen_dialog_token != epcs_rsp.dialog_token) { 412 mlme_err("epcs rsp dialog token %d does not match", 413 epcs_rsp.dialog_token); 414 return QDF_STATUS_E_FAILURE; 415 } 416 417 if (epcs_rsp.status) { 418 mlme_err("epcs rsp status error %d", epcs_rsp.status); 419 return QDF_STATUS_E_FAILURE; 420 } 421 422 edca_info = &epcs_rsp.pa_info; 423 for (i = 0; i < edca_info->num_links; i++) { 424 link = &edca_info->link_info[i]; 425 link_vdev = mlo_get_vdev_by_link_id(vdev, link->link_id, 426 WLAN_MLO_MGR_ID); 427 if (!link_vdev) 428 continue; 429 430 if (link->edca_ie_present) 431 epcs_update_edca_param(link_vdev, &link->edca); 432 else if (link->ven_wme_ie_present) 433 epcs_update_ven_wmm_param(link_vdev, 434 &link->ven_wme_ie_bytes[0]); 435 else 436 epcs_update_def_edca_param(link_vdev); 437 438 if (link->muedca_ie_present) 439 epcs_update_mu_edca_param(link_vdev, &link->muedca); 440 441 wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLO_MGR_ID); 442 } 443 444 epcs_info->state = EPCS_ENABLE; 445 mlme_debug("EPCS (initiator) state: Teardown -> Enable"); 446 447 return status; 448 } 449 450 static QDF_STATUS epcs_handle_rx_teardown(struct wlan_objmgr_vdev *vdev, 451 struct wlan_objmgr_peer *peer, 452 void *event_data, uint32_t len) 453 { 454 struct wlan_mlo_peer_context *ml_peer; 455 struct wlan_mlo_peer_epcs_info *epcs_info; 456 struct wlan_epcs_info epcs_req = {0}; 457 struct mac_context *mac_ctx; 458 QDF_STATUS status; 459 460 if (!vdev || !peer) 461 return QDF_STATUS_E_INVAL; 462 463 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 464 if (!mac_ctx) 465 return QDF_STATUS_E_INVAL; 466 467 ml_peer = peer->mlo_peer_ctx; 468 if (!ml_peer) 469 return QDF_STATUS_E_FAILURE; 470 471 epcs_info = &ml_peer->epcs_info; 472 if (epcs_info->state == EPCS_DOWN) { 473 mlme_err("EPCS has been down, ignore the teardown req."); 474 return QDF_STATUS_E_ALREADY; 475 } 476 477 status = wlan_mlo_parse_epcs_action_frame(&epcs_req, event_data, len); 478 if (status != QDF_STATUS_SUCCESS) { 479 mlme_err("Unable to parse EPCS teardown action frame"); 480 return QDF_STATUS_E_FAILURE; 481 } 482 483 epcs_restore_edca_param(vdev); 484 485 epcs_info->state = EPCS_DOWN; 486 mlme_debug("EPCS state: Enale -> Teardown."); 487 488 return QDF_STATUS_SUCCESS; 489 } 490 491 static QDF_STATUS epcs_handle_tx_req(struct wlan_objmgr_vdev *vdev) 492 { 493 struct wlan_mlo_peer_context *ml_peer; 494 struct wlan_objmgr_peer *peer; 495 struct wlan_action_frame_args args; 496 struct wlan_mlo_peer_epcs_info *epcs_info; 497 QDF_STATUS status; 498 499 if (!vdev) 500 return QDF_STATUS_E_NULL_VALUE; 501 502 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID); 503 if (!peer) 504 return QDF_STATUS_E_NULL_VALUE; 505 506 ml_peer = peer->mlo_peer_ctx; 507 if (!ml_peer) { 508 status = QDF_STATUS_E_NULL_VALUE; 509 goto release_peer; 510 } 511 512 epcs_info = &ml_peer->epcs_info; 513 if (epcs_info->state == EPCS_ENABLE) { 514 mlme_err("EPCS has been enable, ignore the req cmd."); 515 status = QDF_STATUS_E_ALREADY; 516 goto release_peer; 517 } 518 519 args.category = ACTION_CATEGORY_PROTECTED_EHT; 520 args.action = EHT_EPCS_REQUEST; 521 args.arg1 = epcs_gen_dialog_token(epcs_info); 522 523 status = lim_send_epcs_action_req_frame(vdev, 524 wlan_peer_get_macaddr(peer), 525 &args); 526 if (QDF_IS_STATUS_ERROR(status)) 527 mlme_err("Failed to send EPCS action request frame"); 528 529 release_peer: 530 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 531 532 return status; 533 } 534 535 static QDF_STATUS epcs_handle_tx_teardown(struct wlan_objmgr_vdev *vdev) 536 { 537 struct wlan_mlo_peer_context *ml_peer; 538 struct wlan_objmgr_peer *peer; 539 struct wlan_action_frame_args args; 540 struct wlan_mlo_peer_epcs_info *epcs_info; 541 QDF_STATUS status; 542 543 if (!vdev) 544 return QDF_STATUS_E_NULL_VALUE; 545 546 peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID); 547 if (!peer) 548 return QDF_STATUS_E_NULL_VALUE; 549 550 ml_peer = peer->mlo_peer_ctx; 551 if (!ml_peer) { 552 status = QDF_STATUS_E_NULL_VALUE; 553 goto release_peer; 554 } 555 556 epcs_info = &ml_peer->epcs_info; 557 if (epcs_info->state == EPCS_DOWN) { 558 mlme_err("EPCS has been down, ignore the teardwon cmd."); 559 status = QDF_STATUS_E_ALREADY; 560 goto release_peer; 561 } 562 563 args.category = ACTION_CATEGORY_PROTECTED_EHT; 564 args.action = EHT_EPCS_TEARDOWN; 565 566 status = 567 lim_send_epcs_action_teardown_frame(vdev, 568 wlan_peer_get_macaddr(peer), 569 &args); 570 if (QDF_IS_STATUS_ERROR(status)) { 571 mlme_err("Failed to send EPCS tear down frame"); 572 } else { 573 epcs_restore_edca_param(vdev); 574 epcs_info->state = EPCS_DOWN; 575 mlme_debug("EPCS state: Enale -> Teardown."); 576 } 577 578 release_peer: 579 wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); 580 581 return status; 582 } 583 584 static QDF_STATUS epcs_deliver_event(struct wlan_objmgr_vdev *vdev, 585 struct wlan_objmgr_peer *peer, 586 enum wlan_epcs_evt event, 587 void *event_data, uint32_t len) 588 { 589 QDF_STATUS status; 590 591 mlme_debug("EPCS event received: %s(%d)", 592 epcs_get_event_str(event), event); 593 594 switch (event) { 595 case WLAN_EPCS_EV_ACTION_FRAME_RX_REQ: 596 status = epcs_handle_rx_req(vdev, peer, event_data, len); 597 break; 598 case WLAN_EPCS_EV_ACTION_FRAME_RX_RESP: 599 status = epcs_handle_rx_resp(vdev, peer, event_data, len); 600 break; 601 case WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN: 602 status = epcs_handle_rx_teardown(vdev, peer, event_data, len); 603 break; 604 default: 605 status = QDF_STATUS_E_FAILURE; 606 mlme_err("Unhandled EPCS event"); 607 } 608 609 return status; 610 } 611 612 QDF_STATUS wlan_epcs_deliver_event(struct wlan_objmgr_vdev *vdev, 613 struct wlan_objmgr_peer *peer, 614 enum wlan_epcs_evt event, 615 void *event_data, uint32_t len) 616 { 617 return epcs_deliver_event(vdev, peer, event, event_data, len); 618 } 619 620 static QDF_STATUS epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev, 621 enum wlan_epcs_evt event) 622 { 623 QDF_STATUS status; 624 625 mlme_debug("EPCS cmd received: %s(%d)", 626 epcs_get_event_str(event), event); 627 628 switch (event) { 629 case WLAN_EPCS_EV_ACTION_FRAME_TX_REQ: 630 status = epcs_handle_tx_req(vdev); 631 break; 632 case WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN: 633 status = epcs_handle_tx_teardown(vdev); 634 break; 635 default: 636 status = QDF_STATUS_E_FAILURE; 637 mlme_err("Unhandled EPCS cmd"); 638 } 639 640 return status; 641 } 642 643 QDF_STATUS wlan_epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev, 644 enum wlan_epcs_evt event) 645 { 646 if (!vdev) 647 return QDF_STATUS_E_FAILURE; 648 649 if (!wlan_mlme_get_epcs_capability(wlan_vdev_get_psoc(vdev))) { 650 mlme_info("EPCS has been disabled"); 651 return QDF_STATUS_E_FAILURE; 652 } 653 654 return epcs_deliver_cmd(vdev, event); 655 } 656 657 QDF_STATUS wlan_epcs_set_config(struct wlan_objmgr_vdev *vdev, uint8_t flag) 658 { 659 struct mac_context *mac_ctx; 660 661 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 662 if (!mac_ctx) 663 return QDF_STATUS_E_INVAL; 664 665 if (!vdev) 666 return QDF_STATUS_E_FAILURE; 667 668 if (flag) 669 wlan_mlme_set_epcs_capability(wlan_vdev_get_psoc(vdev), true); 670 else 671 wlan_mlme_set_epcs_capability(wlan_vdev_get_psoc(vdev), false); 672 673 return lim_send_eht_caps_ie(mac_ctx, NULL, QDF_STA_MODE, 674 wlan_vdev_get_id(vdev)); 675 } 676 677 bool wlan_epcs_get_config(struct wlan_objmgr_vdev *vdev) 678 { 679 bool epcs_flag; 680 681 if (!vdev) 682 return false; 683 684 epcs_flag = wlan_mlme_get_epcs_capability(wlan_vdev_get_psoc(vdev)); 685 mlme_debug("EPCS %s", epcs_flag ? "Enabled" : "Disabled"); 686 687 return epcs_flag; 688 } 689