1 /* 2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * DOC: sme_qos.c 22 * 23 * Implementation for SME QoS APIs 24 */ 25 /* $Header$ */ 26 /* Include Files */ 27 28 #include "ani_global.h" 29 30 #include "sme_inside.h" 31 #include "csr_inside_api.h" 32 #include "host_diag_core_event.h" 33 #include "host_diag_core_log.h" 34 35 #include "utils_parser.h" 36 #include "sme_power_save_api.h" 37 #include "wlan_mlme_ucfg_api.h" 38 #include "wlan_cm_roam_api.h" 39 40 #ifndef WLAN_MDM_CODE_REDUCTION_OPT 41 /* TODO : 6Mbps as Cisco APs seem to like only this value; analysis req. */ 42 #define SME_QOS_MIN_PHY_RATE 0x5B8D80 43 #define SME_QOS_SURPLUS_BW_ALLOWANCE 0x2000 /* Ratio of 1.0 */ 44 /* Max values to bound tspec params against and avoid rollover */ 45 #define SME_QOS_32BIT_MAX 0xFFFFFFFF 46 #define SME_QOS_16BIT_MAX 0xFFFF 47 #define SME_QOS_16BIT_MSB 0x8000 48 /* Adds y to x, but saturates at 32-bit max to avoid rollover */ 49 #define SME_QOS_BOUNDED_U32_ADD_Y_TO_X(_x, _y) \ 50 do { \ 51 (_x) = ((SME_QOS_32BIT_MAX - (_x)) < (_y)) ? \ 52 (SME_QOS_32BIT_MAX) : (_x) + (_y); \ 53 } while (0) 54 55 /* 56 * As per WMM spec there could be max 2 TSPEC running on the same AC with 57 * different direction. We will refer each TSPEC with an index 58 */ 59 #define SME_QOS_TSPEC_INDEX_0 0 60 #define SME_QOS_TSPEC_INDEX_1 1 61 #define SME_QOS_TSPEC_INDEX_MAX 2 62 #define SME_QOS_TSPEC_MASK_BIT_1_SET 1 63 #define SME_QOS_TSPEC_MASK_BIT_2_SET 2 64 #define SME_QOS_TSPEC_MASK_BIT_1_2_SET 3 65 #define SME_QOS_TSPEC_MASK_CLEAR 0 66 67 /* which key to search on, in the flowlist (1 = flowID, 2 = AC, 4 = reason) */ 68 #define SME_QOS_SEARCH_KEY_INDEX_1 1 69 #define SME_QOS_SEARCH_KEY_INDEX_2 2 70 #define SME_QOS_SEARCH_KEY_INDEX_3 4 71 #define SME_QOS_SEARCH_KEY_INDEX_4 8 /* ac + direction */ 72 #define SME_QOS_SEARCH_KEY_INDEX_5 0x10 /* ac + tspec_mask */ 73 /* special value for searching any Session Id */ 74 #define SME_QOS_SEARCH_SESSION_ID_ANY WLAN_MAX_VDEVS 75 #define SME_QOS_ACCESS_POLICY_EDCA 1 76 #define SME_QOS_MAX_TID 255 77 #define SME_QOS_TSPEC_IE_LENGTH 61 78 #define SME_QOS_TSPEC_IE_TYPE 2 79 #define SME_QOS_MIN_FLOW_ID 1 80 #define SME_QOS_MAX_FLOW_ID 0xFFFFFFFE 81 #define SME_QOS_INVALID_FLOW_ID 0xFFFFFFFF 82 /* per the WMM Specification v1.2 Section 2.2.10 */ 83 /* The Dialog Token field shall be set [...] to a non-zero value */ 84 #define SME_QOS_MIN_DIALOG_TOKEN 1 85 #define SME_QOS_MAX_DIALOG_TOKEN 0xFF 86 87 #ifdef WLAN_FEATURE_MSCS 88 #define MSCS_USER_PRIORITY 0x07C0 89 #define MSCS_STREAM_TIMEOUT 60 /* in sec */ 90 #define MSCS_TCLAS_CLASSIFIER_MASK 0x5F 91 #define MSCS_TCLAS_CLASSIFIER_TYPE 4 92 #endif 93 94 /* Type declarations */ 95 /* Enumeration of the various states in the QoS state m/c */ 96 enum sme_qos_states { 97 SME_QOS_CLOSED = 0, 98 SME_QOS_INIT, 99 SME_QOS_LINK_UP, 100 SME_QOS_REQUESTED, 101 SME_QOS_QOS_ON, 102 SME_QOS_HANDOFF, 103 104 }; 105 /* Enumeration of the various Release QoS trigger */ 106 enum sme_qosrel_triggers { 107 SME_QOS_RELEASE_DEFAULT = 0, 108 SME_QOS_RELEASE_BY_AP, 109 }; 110 /* Enumeration of the various QoS cmds */ 111 enum sme_qos_cmdtype { 112 SME_QOS_SETUP_REQ = 0, 113 SME_QOS_RELEASE_REQ, 114 SME_QOS_MODIFY_REQ, 115 SME_QOS_RESEND_REQ, 116 SME_QOS_CMD_MAX 117 }; 118 /* Enumeration of the various QoS reason codes to be used in the Flow list */ 119 enum sme_qos_reasontype { 120 SME_QOS_REASON_SETUP = 0, 121 SME_QOS_REASON_RELEASE, 122 SME_QOS_REASON_MODIFY, 123 SME_QOS_REASON_MODIFY_PENDING, 124 SME_QOS_REASON_REQ_SUCCESS, 125 SME_QOS_REASON_MAX 126 }; 127 128 /* Table to map user priority passed in as an argument to appropriate Access 129 * Category as specified in 802.11e/WMM 130 */ 131 enum qca_wlan_ac_type sme_qos_up_to_ac_map[SME_QOS_WMM_UP_MAX] = { 132 QCA_WLAN_AC_BE, /* User Priority 0 */ 133 QCA_WLAN_AC_BK, /* User Priority 1 */ 134 QCA_WLAN_AC_BK, /* User Priority 2 */ 135 QCA_WLAN_AC_BE, /* User Priority 3 */ 136 QCA_WLAN_AC_VI, /* User Priority 4 */ 137 QCA_WLAN_AC_VI, /* User Priority 5 */ 138 QCA_WLAN_AC_VO, /* User Priority 6 */ 139 QCA_WLAN_AC_VO /* User Priority 7 */ 140 }; 141 142 /* 143 * DESCRIPTION 144 * SME QoS module's FLOW Link List structure. This list can hold information 145 * per flow/request, like TSPEC params requested, which AC it is running on 146 */ 147 struct sme_qos_flowinfoentry { 148 tListElem link; /* list links */ 149 uint8_t sessionId; 150 uint8_t tspec_mask; 151 enum sme_qos_reasontype reason; 152 uint32_t QosFlowID; 153 enum qca_wlan_ac_type ac_type; 154 struct sme_qos_wmmtspecinfo QoSInfo; 155 void *HDDcontext; 156 sme_QosCallback QoSCallback; 157 bool hoRenewal; /* set to true while re-negotiating flows after */ 158 /* handoff, will set to false once done with */ 159 /* the process. Helps SME to decide if at all */ 160 /* to notify HDD/LIS for flow renewal after HO */ 161 }; 162 /* 163 * DESCRIPTION 164 * SME QoS module's setup request cmd related information structure. 165 */ 166 struct sme_qos_setupcmdinfo { 167 uint32_t QosFlowID; 168 struct sme_qos_wmmtspecinfo QoSInfo; 169 void *HDDcontext; 170 sme_QosCallback QoSCallback; 171 enum sme_qos_wmmuptype UPType; 172 bool hoRenewal; /* set to true while re-negotiating flows after */ 173 /* handoff, will set to false once done with */ 174 /* the process. Helps SME to decide if at all */ 175 /* to notify HDD/LIS for flow renewal after HO */ 176 }; 177 /* 178 * DESCRIPTION 179 * SME QoS module's modify cmd related information structure. 180 */ 181 struct sme_qos_modifycmdinfo { 182 uint32_t QosFlowID; 183 enum qca_wlan_ac_type ac; 184 struct sme_qos_wmmtspecinfo QoSInfo; 185 }; 186 /* 187 * DESCRIPTION 188 * SME QoS module's resend cmd related information structure. 189 */ 190 struct sme_qos_resendcmdinfo { 191 uint8_t tspecMask; 192 enum qca_wlan_ac_type ac; 193 struct sme_qos_wmmtspecinfo QoSInfo; 194 }; 195 /* 196 * DESCRIPTION 197 * SME QoS module's release cmd related information structure. 198 */ 199 struct sme_qos_releasecmdinfo { 200 uint32_t QosFlowID; 201 }; 202 /* 203 * DESCRIPTION 204 * SME QoS module's buffered cmd related information structure. 205 */ 206 struct sme_qos_cmdinfo { 207 enum sme_qos_cmdtype command; 208 struct mac_context *mac; 209 uint8_t sessionId; 210 union { 211 struct sme_qos_setupcmdinfo setupCmdInfo; 212 struct sme_qos_modifycmdinfo modifyCmdInfo; 213 struct sme_qos_resendcmdinfo resendCmdInfo; 214 struct sme_qos_releasecmdinfo releaseCmdInfo; 215 } u; 216 }; 217 /* 218 * DESCRIPTION 219 * SME QoS module's buffered cmd List structure. This list can hold information 220 * related to any pending cmd from HDD 221 */ 222 struct sme_qos_cmdinfoentry { 223 tListElem link; /* list links */ 224 struct sme_qos_cmdinfo cmdInfo; 225 }; 226 /* 227 * DESCRIPTION 228 * SME QoS module's Per AC information structure. This can hold information on 229 * how many flows running on the AC, the current, previous states the AC is in 230 */ 231 struct sme_qos_acinfo { 232 uint8_t num_flows[SME_QOS_TSPEC_INDEX_MAX]; 233 enum sme_qos_states curr_state; 234 enum sme_qos_states prev_state; 235 struct sme_qos_wmmtspecinfo curr_QoSInfo[SME_QOS_TSPEC_INDEX_MAX]; 236 struct sme_qos_wmmtspecinfo requested_QoSInfo[SME_QOS_TSPEC_INDEX_MAX]; 237 /* reassoc requested for APSD */ 238 bool reassoc_pending; 239 /* 240 * As per WMM spec there could be max 2 TSPEC running on the same 241 * AC with different direction. We will refer each TSPEC with an index 242 */ 243 /* status showing if both the indices are in use */ 244 uint8_t tspec_mask_status; 245 /* tspec negotiation going on for which index */ 246 uint8_t tspec_pending; 247 /* set to true while re-negotiating flows after */ 248 bool hoRenewal; 249 /* 250 * handoff, will set to false once done with the process. Helps SME to 251 * decide if at all to notify HDD/LIS for flow renewal after HO 252 */ 253 uint8_t ricIdentifier[SME_QOS_TSPEC_INDEX_MAX]; 254 /* 255 * stores the ADD TS response for each AC. The ADD TS response is 256 * formed by parsing the RIC received in the the reassoc response 257 */ 258 tSirAddtsRsp addTsRsp[SME_QOS_TSPEC_INDEX_MAX]; 259 enum sme_qosrel_triggers relTrig; 260 261 }; 262 /* 263 * DESCRIPTION 264 * SME QoS module's Per session information structure. This can hold 265 * information on the state of the session 266 */ 267 struct sme_qos_sessioninfo { 268 /* what is this entry's session id */ 269 uint8_t sessionId; 270 /* is the session currently active */ 271 bool sessionActive; 272 /* All AC info for this session */ 273 struct sme_qos_acinfo ac_info[QCA_WLAN_AC_ALL]; 274 /* Bitmask of the ACs with APSD on */ 275 /* Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored */ 276 uint8_t apsdMask; 277 /* association information for this session */ 278 sme_QosAssocInfo assocInfo; 279 /* ID assigned to our reassoc request */ 280 uint32_t roamID; 281 /* are we in the process of handing off to a different AP */ 282 bool handoffRequested; 283 /* commands that are being buffered for this session */ 284 tDblLinkList bufferedCommandList; 285 286 bool ftHandoffInProgress; 287 288 }; 289 /* 290 * DESCRIPTION 291 * Search key union. We can use the flowID, ac type, or reason to find an 292 * entry in the flow list 293 */ 294 union sme_qos_searchkey { 295 uint32_t QosFlowID; 296 enum qca_wlan_ac_type ac_type; 297 enum sme_qos_reasontype reason; 298 }; 299 /* 300 * DESCRIPTION 301 * We can either use the flowID or the ac type to find an entry in the flow 302 * list. The index is a bitmap telling us which key to use. Starting from LSB, 303 * bit 0 - Flow ID 304 * bit 1 - AC type 305 */ 306 struct sme_qos_searchinfo { 307 uint8_t sessionId; 308 uint8_t index; 309 union sme_qos_searchkey key; 310 enum sme_qos_wmm_dir_type direction; 311 uint8_t tspec_mask; 312 }; 313 314 typedef QDF_STATUS (*sme_QosProcessSearchEntry)(struct mac_context *mac, 315 tListElem *pEntry); 316 317 static enum sme_qos_statustype sme_qos_internal_setup_req(struct mac_context *mac, 318 uint8_t sessionId, 319 struct sme_qos_wmmtspecinfo *pQoSInfo, 320 sme_QosCallback QoSCallback, 321 void *HDDcontext, 322 enum sme_qos_wmmuptype UPType, 323 uint32_t QosFlowID, 324 bool buffered_cmd, bool hoRenewal); 325 static enum sme_qos_statustype sme_qos_internal_modify_req(struct mac_context *mac, 326 struct sme_qos_wmmtspecinfo *pQoSInfo, 327 uint32_t QosFlowID, 328 bool buffered_cmd); 329 static enum sme_qos_statustype sme_qos_internal_release_req(struct mac_context *mac, 330 uint8_t session_id, 331 uint32_t QosFlowID, 332 bool buffered_cmd); 333 static enum sme_qos_statustype sme_qos_setup(struct mac_context *mac, 334 uint8_t sessionId, 335 struct sme_qos_wmmtspecinfo *pTspec_Info, 336 enum qca_wlan_ac_type ac); 337 static QDF_STATUS sme_qos_add_ts_req(struct mac_context *mac, 338 uint8_t sessionId, 339 struct sme_qos_wmmtspecinfo *pTspec_Info, 340 enum qca_wlan_ac_type ac); 341 static QDF_STATUS sme_qos_del_ts_req(struct mac_context *mac, 342 uint8_t sessionId, 343 enum qca_wlan_ac_type ac, uint8_t tspec_mask); 344 static QDF_STATUS sme_qos_process_add_ts_rsp(struct mac_context *mac, 345 void *msg_buf); 346 static QDF_STATUS sme_qos_process_del_ts_ind(struct mac_context *mac, 347 void *msg_buf); 348 static QDF_STATUS sme_qos_process_del_ts_rsp(struct mac_context *mac, 349 void *msg_buf); 350 static QDF_STATUS sme_qos_process_assoc_complete_ev(struct mac_context *mac, 351 uint8_t sessionId, void *pEvent_info); 352 static QDF_STATUS sme_qos_process_reassoc_req_ev(struct mac_context *mac, 353 uint8_t sessionId, void *pEvent_info); 354 static QDF_STATUS sme_qos_process_reassoc_success_ev(struct mac_context *mac, 355 uint8_t sessionId, void *pEvent_info); 356 static QDF_STATUS sme_qos_process_reassoc_failure_ev(struct mac_context *mac, 357 uint8_t sessionId, void *pEvent_info); 358 static QDF_STATUS sme_qos_process_disconnect_ev(struct mac_context *mac, uint8_t 359 sessionId, void *pEvent_info); 360 static QDF_STATUS sme_qos_process_join_req_ev(struct mac_context *mac, uint8_t 361 sessionId, void *pEvent_info); 362 static QDF_STATUS sme_qos_process_handoff_assoc_req_ev(struct mac_context *mac, 363 uint8_t sessionId, 364 void *pEvent_info); 365 static QDF_STATUS sme_qos_process_handoff_success_ev(struct mac_context *mac, 366 uint8_t sessionId, void *pEvent_info); 367 static QDF_STATUS sme_qos_process_preauth_success_ind(struct mac_context *mac, 368 uint8_t sessionId, 369 void *pEvent_info); 370 static QDF_STATUS sme_qos_process_set_key_success_ind(struct mac_context *mac, 371 uint8_t sessionId, 372 void *pEvent_info); 373 static QDF_STATUS sme_qos_process_aggr_qos_rsp(struct mac_context *mac, 374 void *msg_buf); 375 static QDF_STATUS sme_qos_ft_aggr_qos_req(struct mac_context *mac, uint8_t 376 sessionId); 377 static QDF_STATUS sme_qos_process_add_ts_success_rsp(struct mac_context *mac, 378 uint8_t sessionId, 379 tSirAddtsRspInfo *pRsp); 380 static QDF_STATUS sme_qos_process_add_ts_failure_rsp(struct mac_context *mac, 381 uint8_t sessionId, 382 tSirAddtsRspInfo *pRsp); 383 static QDF_STATUS sme_qos_aggregate_params( 384 struct sme_qos_wmmtspecinfo *pInput_Tspec_Info, 385 struct sme_qos_wmmtspecinfo *pCurrent_Tspec_Info, 386 struct sme_qos_wmmtspecinfo *pUpdated_Tspec_Info); 387 static QDF_STATUS sme_qos_update_params(uint8_t sessionId, 388 enum qca_wlan_ac_type ac, 389 uint8_t tspec_mask, 390 struct sme_qos_wmmtspecinfo *pTspec_Info); 391 static enum qca_wlan_ac_type sme_qos_up_to_ac(enum sme_qos_wmmuptype up); 392 393 static bool 394 sme_qos_is_acm(struct mac_context *mac, struct bss_description *pSirBssDesc, 395 enum qca_wlan_ac_type ac, tDot11fBeaconIEs *pIes); 396 397 static tListElem *sme_qos_find_in_flow_list(struct sme_qos_searchinfo 398 search_key); 399 static QDF_STATUS sme_qos_find_all_in_flow_list(struct mac_context *mac, 400 struct sme_qos_searchinfo search_key, 401 sme_QosProcessSearchEntry fnp); 402 static void sme_qos_state_transition(uint8_t sessionId, 403 enum qca_wlan_ac_type ac, 404 enum sme_qos_states new_state); 405 static QDF_STATUS sme_qos_buffer_cmd(struct sme_qos_cmdinfo *pcmd, bool 406 insert_head); 407 static QDF_STATUS sme_qos_process_buffered_cmd(uint8_t sessionId); 408 static QDF_STATUS sme_qos_save_assoc_info(struct sme_qos_sessioninfo *pSession, 409 sme_QosAssocInfo *pAssoc_info); 410 static QDF_STATUS sme_qos_setup_fnp(struct mac_context *mac, tListElem *pEntry); 411 static QDF_STATUS sme_qos_modification_notify_fnp(struct mac_context *mac, 412 tListElem *pEntry); 413 static QDF_STATUS sme_qos_modify_fnp(struct mac_context *mac, tListElem *pEntry); 414 static QDF_STATUS sme_qos_del_ts_ind_fnp(struct mac_context *mac, tListElem 415 *pEntry); 416 static QDF_STATUS sme_qos_reassoc_success_ev_fnp(struct mac_context *mac, 417 tListElem *pEntry); 418 static QDF_STATUS sme_qos_add_ts_failure_fnp(struct mac_context *mac, tListElem 419 *pEntry); 420 static QDF_STATUS sme_qos_add_ts_success_fnp(struct mac_context *mac, tListElem 421 *pEntry); 422 static bool sme_qos_is_rsp_pending(uint8_t sessionId, enum qca_wlan_ac_type ac); 423 static bool sme_qos_is_uapsd_active(void); 424 425 static QDF_STATUS sme_qos_buffer_existing_flows(struct mac_context *mac, 426 uint8_t sessionId); 427 static QDF_STATUS sme_qos_delete_existing_flows(struct mac_context *mac, 428 uint8_t sessionId); 429 static void sme_qos_cleanup_ctrl_blk_for_handoff(struct mac_context *mac, 430 uint8_t sessionId); 431 static QDF_STATUS sme_qos_delete_buffered_requests(struct mac_context *mac, 432 uint8_t sessionId); 433 static bool sme_qos_validate_requested_params(struct mac_context *mac, 434 struct sme_qos_wmmtspecinfo *pQoSInfo, 435 uint8_t sessionId); 436 437 static QDF_STATUS qos_issue_command(struct mac_context *mac, uint8_t sessionId, 438 eSmeCommandType cmdType, 439 struct sme_qos_wmmtspecinfo *pQoSInfo, 440 enum qca_wlan_ac_type ac, uint8_t tspec_mask); 441 /* sme_qos_re_request_add_ts to re-send AddTS for the combined QoS request */ 442 static enum sme_qos_statustype sme_qos_re_request_add_ts(struct mac_context *mac, 443 uint8_t sessionId, 444 struct sme_qos_wmmtspecinfo *pQoSInfo, 445 enum qca_wlan_ac_type ac, 446 uint8_t tspecMask); 447 static void sme_qos_init_a_cs(struct mac_context *mac, uint8_t sessionId); 448 static QDF_STATUS sme_qos_request_reassoc(struct mac_context *mac, 449 uint8_t sessionId, 450 tCsrRoamModifyProfileFields * 451 pModFields, bool fForce); 452 static uint32_t sme_qos_assign_flow_id(void); 453 static uint8_t sme_qos_assign_dialog_token(void); 454 static QDF_STATUS sme_qos_update_tspec_mask(uint8_t sessionId, 455 struct sme_qos_searchinfo search_key, 456 uint8_t new_tspec_mask); 457 458 /* 459 * DESCRIPTION 460 * SME QoS module's internal control block. 461 */ 462 struct sme_qos_cb_s { 463 /* global Mac pointer */ 464 struct mac_context *mac; 465 /* All Session Info */ 466 struct sme_qos_sessioninfo *sessionInfo; 467 /* All FLOW info */ 468 tDblLinkList flow_list; 469 /* default TSPEC params */ 470 struct sme_qos_wmmtspecinfo *def_QoSInfo; 471 /* counter for assigning Flow IDs */ 472 uint32_t nextFlowId; 473 /* counter for assigning Dialog Tokens */ 474 uint8_t nextDialogToken; 475 } sme_qos_cb; 476 477 #ifdef WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY 478 static inline QDF_STATUS sme_qos_allocate_control_block_buffer(void) 479 { 480 uint32_t buf_size; 481 482 buf_size = WLAN_MAX_VDEVS * sizeof(struct sme_qos_sessioninfo); 483 sme_qos_cb.sessionInfo = qdf_mem_malloc(buf_size); 484 if (!sme_qos_cb.sessionInfo) 485 return QDF_STATUS_E_NOMEM; 486 487 buf_size = QCA_WLAN_AC_ALL * sizeof(struct sme_qos_wmmtspecinfo); 488 sme_qos_cb.def_QoSInfo = qdf_mem_malloc(buf_size); 489 490 if (!sme_qos_cb.def_QoSInfo) { 491 qdf_mem_free(sme_qos_cb.sessionInfo); 492 return QDF_STATUS_E_NOMEM; 493 } 494 495 return QDF_STATUS_SUCCESS; 496 } 497 498 static inline void sme_qos_free_control_block_buffer(void) 499 { 500 qdf_mem_free(sme_qos_cb.sessionInfo); 501 sme_qos_cb.sessionInfo = NULL; 502 503 qdf_mem_free(sme_qos_cb.def_QoSInfo); 504 sme_qos_cb.def_QoSInfo = NULL; 505 } 506 507 #else /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ 508 509 struct sme_qos_sessioninfo sessionInfo[WLAN_MAX_VDEVS]; 510 struct sme_qos_wmmtspecinfo def_QoSInfo[QCA_WLAN_AC_ALL]; 511 512 static inline QDF_STATUS sme_qos_allocate_control_block_buffer(void) 513 { 514 qdf_mem_zero(&sessionInfo, sizeof(sessionInfo)); 515 sme_qos_cb.sessionInfo = sessionInfo; 516 qdf_mem_zero(&def_QoSInfo, sizeof(def_QoSInfo)); 517 sme_qos_cb.def_QoSInfo = def_QoSInfo; 518 519 return QDF_STATUS_SUCCESS; 520 } 521 522 static inline void sme_qos_free_control_block_buffer(void) 523 { 524 sme_qos_cb.sessionInfo = NULL; 525 sme_qos_cb.def_QoSInfo = NULL; 526 } 527 #endif /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ 528 529 /* External APIs definitions */ 530 531 /** 532 * sme_qos_open() - called to initialize SME QoS module. 533 * @mac: global MAC context 534 * 535 * This function must be called before any API call to 536 * SME QoS module. 537 * 538 * Return: QDF_STATUS 539 */ 540 QDF_STATUS sme_qos_open(struct mac_context *mac) 541 { 542 struct sme_qos_sessioninfo *pSession; 543 uint8_t sessionId; 544 QDF_STATUS status; 545 546 sme_debug("Initializing SME-QoS module"); 547 /* alloc and init the control block */ 548 /* (note that this will make all sessions invalid) */ 549 if (!QDF_IS_STATUS_SUCCESS(sme_qos_allocate_control_block_buffer())) { 550 sme_err("Failed to allocate buffer"); 551 return QDF_STATUS_E_NOMEM; 552 } 553 sme_qos_cb.mac = mac; 554 sme_qos_cb.nextFlowId = SME_QOS_MIN_FLOW_ID; 555 sme_qos_cb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN; 556 557 /* init flow list */ 558 status = csr_ll_open(&sme_qos_cb.flow_list); 559 if (!QDF_IS_STATUS_SUCCESS(status)) { 560 sme_err("cannot initialize Flow List"); 561 sme_qos_free_control_block_buffer(); 562 return QDF_STATUS_E_FAILURE; 563 } 564 565 for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; ++sessionId) { 566 pSession = &sme_qos_cb.sessionInfo[sessionId]; 567 pSession->sessionId = sessionId; 568 /* initialize the session's per-AC information */ 569 sme_qos_init_a_cs(mac, sessionId); 570 /* initialize the session's buffered command list */ 571 status = csr_ll_open(&pSession->bufferedCommandList); 572 if (!QDF_IS_STATUS_SUCCESS(status)) { 573 sme_err("cannot initialize cmd list for session %d", 574 sessionId); 575 sme_qos_free_control_block_buffer(); 576 return QDF_STATUS_E_FAILURE; 577 } 578 } 579 580 sme_debug("done initializing SME-QoS module"); 581 return QDF_STATUS_SUCCESS; 582 } 583 584 /* 585 * sme_qos_close() - To close down SME QoS module. There should not be 586 * any API call into this module after calling this function until another 587 * call of sme_qos_open. 588 * 589 * mac - Pointer to the global MAC parameter structure. 590 * Return QDF_STATUS 591 */ 592 QDF_STATUS sme_qos_close(struct mac_context *mac) 593 { 594 struct sme_qos_sessioninfo *pSession; 595 enum qca_wlan_ac_type ac; 596 uint8_t sessionId; 597 598 sme_debug("closing down SME-QoS"); 599 600 /* cleanup control block */ 601 /* close the flow list */ 602 csr_ll_close(&sme_qos_cb.flow_list); 603 /* shut down all of the sessions */ 604 for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; ++sessionId) { 605 pSession = &sme_qos_cb.sessionInfo[sessionId]; 606 if (!pSession) 607 continue; 608 609 sme_qos_init_a_cs(mac, sessionId); 610 /* this session doesn't require UAPSD */ 611 pSession->apsdMask = 0; 612 613 pSession->handoffRequested = false; 614 pSession->roamID = 0; 615 /* need to clean up buffered req */ 616 sme_qos_delete_buffered_requests(mac, sessionId); 617 /* need to clean up flows */ 618 sme_qos_delete_existing_flows(mac, sessionId); 619 620 /* Clean up the assoc info if already allocated */ 621 if (pSession->assocInfo.bss_desc) { 622 qdf_mem_free(pSession->assocInfo.bss_desc); 623 pSession->assocInfo.bss_desc = NULL; 624 } 625 /* close the session's buffered command list */ 626 csr_ll_close(&pSession->bufferedCommandList); 627 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) 628 sme_qos_state_transition(sessionId, ac, SME_QOS_CLOSED); 629 630 pSession->sessionActive = false; 631 } 632 sme_qos_free_control_block_buffer(); 633 sme_debug("closed down QoS"); 634 return QDF_STATUS_SUCCESS; 635 } 636 637 /** 638 * sme_qos_setup_req() - The SME QoS API exposed to HDD to request for QoS 639 * on a particular AC. 640 * @mac_handle: The handle returned by mac_open. 641 * @sessionId: sessionId returned by sme_open_session. 642 * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the 643 * WMM TSPEC related info as defined above, provided by HDD 644 * @QoSCallback: The callback which is registered per flow while 645 * requesting for QoS. Used for any notification for the 646 * flow (i.e. setup success/failure/release) which needs to 647 * be sent to HDD 648 * @HDDcontext: A cookie passed by HDD to be used by SME during any QoS 649 * notification (through the callback) to HDD 650 * @UPType: Useful only if HDD or any other upper layer module (BAP etc.) 651 * looking for implicit QoS setup, in that 652 * case, the pQoSInfo will be NULL & SME will know about the AC 653 * (from the UP provided in this param) QoS is requested on 654 * @pQosFlowID: Identification per flow running on each AC generated by 655 * SME. It is only meaningful if the QoS setup for the flow is 656 * successful 657 * This function should be called after a link has been 658 * established, i.e. STA is associated with an AP etc. If the request involves 659 * admission control on the requested AC, HDD needs to provide the necessary 660 * Traffic Specification (TSPEC) parameters otherwise SME is going to use the 661 * default params. 662 * Return: QDF_STATUS_SUCCESS - Setup is successful. 663 * Other status means Setup request failed 664 */ 665 enum sme_qos_statustype sme_qos_setup_req(mac_handle_t mac_handle, 666 uint32_t sessionId, 667 struct sme_qos_wmmtspecinfo *pQoSInfo, 668 sme_QosCallback QoSCallback, 669 void *HDDcontext, 670 enum sme_qos_wmmuptype UPType, 671 uint32_t *pQosFlowID) 672 { 673 struct sme_qos_sessioninfo *pSession; 674 QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; 675 struct mac_context *mac = MAC_CONTEXT(mac_handle); 676 enum sme_qos_statustype status; 677 678 sme_debug("QoS Setup requested by client on session %d", sessionId); 679 lock_status = sme_acquire_global_lock(&mac->sme); 680 if (!QDF_IS_STATUS_SUCCESS(lock_status)) 681 return SME_QOS_STATUS_SETUP_FAILURE_RSP; 682 /* Make sure the session is valid */ 683 if (!CSR_IS_SESSION_VALID(mac, sessionId)) { 684 sme_err("Supplied Session ID %d is invalid", sessionId); 685 status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 686 } else { 687 /* Make sure the session is active */ 688 pSession = &sme_qos_cb.sessionInfo[sessionId]; 689 if (!pSession->sessionActive) { 690 sme_err("Supplied Session ID %d is inactive", 691 sessionId); 692 status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 693 } else { 694 /* Assign a Flow ID */ 695 *pQosFlowID = sme_qos_assign_flow_id(); 696 sme_debug("QoS request on session %d assigned Flow ID %d", 697 sessionId, *pQosFlowID); 698 /* Call the internal function for QoS setup, */ 699 /* adding a layer of abstraction */ 700 status = 701 sme_qos_internal_setup_req(mac, (uint8_t) 702 sessionId, 703 pQoSInfo, QoSCallback, 704 HDDcontext, UPType, 705 *pQosFlowID, false, 706 false); 707 } 708 } 709 sme_release_global_lock(&mac->sme); 710 sme_debug("QoS setup return status on session %d is %d", 711 sessionId, status); 712 return status; 713 } 714 715 /** 716 * sme_qos_modify_req() - The SME QoS API exposed to HDD to request for 717 * modification of certain QoS params on a flow running on a particular AC. 718 * @mac_handle: The handle returned by mac_open. 719 * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the 720 * WMM TSPEC related info as defined above, provided by HDD 721 * @QosFlowID: Identification per flow running on each AC generated by 722 * SME. It is only meaningful if the QoS setup for the flow has 723 * been successful already 724 * 725 * This function should be called after a link has been established, 726 * i.e. STA is associated with an AP etc. & a QoS setup has been successful for 727 * that flow. If the request involves admission control on the requested AC, 728 * HDD needs to provide the necessary Traffic Specification (TSPEC) parameters & 729 * SME might start the renegotiation process through ADDTS. 730 * 731 * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful. 732 * Other status means request failed 733 */ 734 enum sme_qos_statustype sme_qos_modify_req(mac_handle_t mac_handle, 735 struct sme_qos_wmmtspecinfo *pQoSInfo, 736 uint32_t QosFlowID) 737 { 738 QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; 739 struct mac_context *mac = MAC_CONTEXT(mac_handle); 740 enum sme_qos_statustype status; 741 742 sme_debug("QoS Modify requested by client for Flow %d", QosFlowID); 743 lock_status = sme_acquire_global_lock(&mac->sme); 744 if (!QDF_IS_STATUS_SUCCESS(lock_status)) { 745 sme_err("Unable to obtain lock"); 746 return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 747 } 748 /* Call the internal function for QoS modify, adding a 749 * layer of abstraction 750 */ 751 status = sme_qos_internal_modify_req(mac, pQoSInfo, QosFlowID, false); 752 sme_release_global_lock(&mac->sme); 753 sme_debug("QoS Modify return status on Flow %d is %d", 754 QosFlowID, status); 755 return status; 756 } 757 758 /** 759 * sme_qos_release_req() - The SME QoS API exposed to HDD to request for 760 * releasing a QoS flow running on a particular AC. 761 * 762 * @mac_handle: The handle returned by mac_open. 763 * @session_id: session_id returned by sme_open_session. 764 * @QosFlowID: Identification per flow running on each AC generated by SME 765 * It is only meaningful if the QoS setup for the flow is successful 766 * 767 * This function should be called only if a QoS is set up with a valid FlowID. 768 * HDD should invoke this API only if an explicit request for QoS release has 769 * come from Application 770 * 771 * Return: QDF_STATUS_SUCCESS - Release is successful. 772 */ 773 enum sme_qos_statustype sme_qos_release_req(mac_handle_t mac_handle, 774 uint8_t session_id, 775 uint32_t QosFlowID) 776 { 777 QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; 778 struct mac_context *mac = MAC_CONTEXT(mac_handle); 779 enum sme_qos_statustype status; 780 781 sme_debug("QoS Release requested by client for Flow %d", QosFlowID); 782 lock_status = sme_acquire_global_lock(&mac->sme); 783 if (!QDF_IS_STATUS_SUCCESS(lock_status)) { 784 sme_err("Unable to obtain lock"); 785 return SME_QOS_STATUS_RELEASE_FAILURE_RSP; 786 } 787 /* Call the internal function for QoS release, adding a 788 * layer of abstraction 789 */ 790 status = sme_qos_internal_release_req(mac, session_id, QosFlowID, 791 false); 792 sme_release_global_lock(&mac->sme); 793 sme_debug("QoS Release return status on Flow %d is %d", 794 QosFlowID, status); 795 return status; 796 } 797 798 void qos_release_command(struct mac_context *mac, tSmeCmd *pCommand) 799 { 800 qdf_mem_zero(&pCommand->u.qosCmd, sizeof(tGenericQosCmd)); 801 csr_release_command(mac, pCommand); 802 } 803 804 /** 805 * sme_qos_msg_processor() - Processes QOS messages 806 * @mac_ctx: Pointer to the global MAC parameter structure. 807 * @msg_type: the type of msg passed by PE as defined in wni_api.h 808 * @msg: a pointer to a buffer that maps to various structures bases. 809 * 810 * sme_process_msg() calls this function for the messages that 811 * are handled by SME QoS module. 812 * 813 * Return: QDF_STATUS enumeration. 814 */ 815 QDF_STATUS sme_qos_msg_processor(struct mac_context *mac_ctx, 816 uint16_t msg_type, void *msg) 817 { 818 QDF_STATUS status = QDF_STATUS_E_FAILURE; 819 tListElem *entry = NULL; 820 tSmeCmd *command; 821 822 sme_debug("msg = %d for QoS", msg_type); 823 /* switch on the msg type & make the state transition accordingly */ 824 switch (msg_type) { 825 case eWNI_SME_ADDTS_RSP: 826 entry = csr_nonscan_active_ll_peek_head(mac_ctx, 827 LL_ACCESS_LOCK); 828 if (!entry) 829 break; 830 command = GET_BASE_ADDR(entry, tSmeCmd, Link); 831 if (eSmeCommandAddTs == command->command) { 832 status = sme_qos_process_add_ts_rsp(mac_ctx, msg); 833 if (csr_nonscan_active_ll_remove_entry(mac_ctx, entry, 834 LL_ACCESS_LOCK)) { 835 qos_release_command(mac_ctx, command); 836 } 837 } 838 break; 839 case eWNI_SME_DELTS_RSP: 840 entry = csr_nonscan_active_ll_peek_head(mac_ctx, 841 LL_ACCESS_LOCK); 842 if (!entry) 843 break; 844 command = GET_BASE_ADDR(entry, tSmeCmd, Link); 845 if (eSmeCommandDelTs == command->command) { 846 status = sme_qos_process_del_ts_rsp(mac_ctx, msg); 847 if (csr_nonscan_active_ll_remove_entry(mac_ctx, entry, 848 LL_ACCESS_LOCK)) { 849 qos_release_command(mac_ctx, command); 850 } 851 } 852 break; 853 case eWNI_SME_DELTS_IND: 854 status = sme_qos_process_del_ts_ind(mac_ctx, msg); 855 break; 856 case eWNI_SME_FT_AGGR_QOS_RSP: 857 status = sme_qos_process_aggr_qos_rsp(mac_ctx, msg); 858 break; 859 default: 860 /* err msg */ 861 sme_err("unknown msg type = %d", msg_type); 862 break; 863 } 864 return status; 865 } 866 867 /** 868 * sme_qos_process_disconnect_roam_ind() - Delete the existing TSPEC 869 * flows when roaming due to disconnect is complete. 870 * @mac - Pointer to the global MAC parameter structure. 871 * @vdev_id: Vdev id 872 * 873 * Return: None 874 */ 875 static void 876 sme_qos_process_disconnect_roam_ind(struct mac_context *mac, 877 uint8_t vdev_id) 878 { 879 sme_qos_delete_existing_flows(mac, vdev_id); 880 } 881 882 /* 883 * sme_qos_csr_event_ind() - The QoS sub-module in SME expects notifications 884 * from CSR when certain events occur as mentioned in sme_qos_csr_event_indType. 885 * 886 * mac - Pointer to the global MAC parameter structure. 887 * ind - The event occurred of type sme_qos_csr_event_indType. 888 * pEvent_info - Information related to the event 889 * Return QDF_STATUS 890 */ 891 QDF_STATUS sme_qos_csr_event_ind(struct mac_context *mac, 892 uint8_t sessionId, 893 sme_qos_csr_event_indType ind, void *pEvent_info) 894 { 895 QDF_STATUS status = QDF_STATUS_E_FAILURE; 896 897 sme_debug("vdev %d event %d", sessionId, ind); 898 switch (ind) { 899 case SME_QOS_CSR_ASSOC_COMPLETE: 900 /* expecting assoc info in pEvent_info */ 901 status = sme_qos_process_assoc_complete_ev(mac, sessionId, 902 pEvent_info); 903 break; 904 case SME_QOS_CSR_REASSOC_REQ: 905 /* nothing expected in pEvent_info */ 906 status = sme_qos_process_reassoc_req_ev(mac, sessionId, 907 pEvent_info); 908 break; 909 case SME_QOS_CSR_REASSOC_COMPLETE: 910 /* expecting assoc info in pEvent_info */ 911 status = 912 sme_qos_process_reassoc_success_ev(mac, sessionId, 913 pEvent_info); 914 break; 915 case SME_QOS_CSR_REASSOC_FAILURE: 916 /* nothing expected in pEvent_info */ 917 status = 918 sme_qos_process_reassoc_failure_ev(mac, sessionId, 919 pEvent_info); 920 break; 921 case SME_QOS_CSR_DISCONNECT_REQ: 922 case SME_QOS_CSR_DISCONNECT_IND: 923 /* nothing expected in pEvent_info */ 924 status = sme_qos_process_disconnect_ev(mac, sessionId, 925 pEvent_info); 926 break; 927 case SME_QOS_CSR_JOIN_REQ: 928 /* nothing expected in pEvent_info */ 929 status = sme_qos_process_join_req_ev(mac, sessionId, 930 pEvent_info); 931 break; 932 case SME_QOS_CSR_HANDOFF_ASSOC_REQ: 933 /* nothing expected in pEvent_info */ 934 status = sme_qos_process_handoff_assoc_req_ev(mac, sessionId, 935 pEvent_info); 936 break; 937 case SME_QOS_CSR_HANDOFF_COMPLETE: 938 /* nothing expected in pEvent_info */ 939 status = 940 sme_qos_process_handoff_success_ev(mac, sessionId, 941 pEvent_info); 942 break; 943 case SME_QOS_CSR_PREAUTH_SUCCESS_IND: 944 status = 945 sme_qos_process_preauth_success_ind(mac, sessionId, 946 pEvent_info); 947 break; 948 case SME_QOS_CSR_SET_KEY_SUCCESS_IND: 949 status = 950 sme_qos_process_set_key_success_ind(mac, sessionId, 951 pEvent_info); 952 break; 953 case SME_QOS_CSR_DISCONNECT_ROAM_COMPLETE: 954 sme_qos_process_disconnect_roam_ind(mac, sessionId); 955 status = QDF_STATUS_SUCCESS; 956 break; 957 default: 958 /* Err msg */ 959 sme_err("On Session %d Unknown Event %d received from CSR", 960 sessionId, ind); 961 break; 962 } 963 964 return status; 965 } 966 967 /* 968 * sme_qos_get_acm_mask() - The QoS sub-module API to find out on which ACs 969 * AP mandates Admission Control (ACM = 1) 970 * (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) 971 * 972 * mac - Pointer to the global MAC parameter structure. 973 * pSirBssDesc - The event occurred of type sme_qos_csr_event_indType. 974 * Return a bit mask indicating for which ACs AP has ACM set to 1 975 */ 976 uint8_t sme_qos_get_acm_mask(struct mac_context *mac, struct bss_description 977 *pSirBssDesc, tDot11fBeaconIEs *pIes) 978 { 979 enum qca_wlan_ac_type ac; 980 uint8_t acm_mask = 0; 981 982 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 983 if (sme_qos_is_acm(mac, pSirBssDesc, ac, pIes)) 984 acm_mask = acm_mask | (1 << (QCA_WLAN_AC_VO - ac)); 985 } 986 987 return acm_mask; 988 } 989 990 /* Internal function definitions */ 991 992 /** 993 * sme_qos_internal_setup_req() - The SME QoS internal setup request handling 994 * function. 995 * 996 * @mac: Pointer to the global MAC parameter structure. 997 * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the 998 * WMM TSPEC related info as defined above, provided by HDD 999 * @QoSCallback: The callback which is registered per flow while 1000 * requesting for QoS. Used for any notification for the 1001 * flow (i.e. setup success/failure/release) which needs to 1002 * be sent to HDD 1003 * @HDDcontext: A cookie passed by HDD to be used by SME during any QoS 1004 * notification (through the callback) to HDD 1005 * @UPType: Useful only if HDD or any other upper layer module (BAP etc.) 1006 * looking for implicit QoS setup, in that 1007 * case, the pQoSInfo will be NULL & SME will know about the AC 1008 * (from the UP provided in this param) QoS is requested on 1009 * @QosFlowID: Identification per flow running on each AC generated by 1010 * SME. It is only meaningful if the QoS setup for the flow is 1011 * successful 1012 * @buffered_cmd: tells us if the cmd was a buffered one or fresh from 1013 * client 1014 * 1015 * If the request involves admission control on the requested AC, HDD needs to 1016 * provide the necessary Traffic Specification (TSPEC) parameters otherwise SME 1017 * is going to use the default params. 1018 * 1019 * Return: QDF_STATUS_SUCCESS - Setup is successful. 1020 * Other status means Setup request failed 1021 */ 1022 static enum sme_qos_statustype sme_qos_internal_setup_req(struct mac_context *mac, 1023 uint8_t sessionId, 1024 struct sme_qos_wmmtspecinfo *pQoSInfo, 1025 sme_QosCallback QoSCallback, 1026 void *HDDcontext, 1027 enum sme_qos_wmmuptype UPType, 1028 uint32_t QosFlowID, 1029 bool buffered_cmd, bool hoRenewal) 1030 { 1031 struct sme_qos_sessioninfo *pSession; 1032 struct sme_qos_acinfo *pACInfo; 1033 enum qca_wlan_ac_type ac; 1034 struct sme_qos_wmmtspecinfo Tspec_Info; 1035 enum sme_qos_states new_state = SME_QOS_CLOSED; 1036 struct sme_qos_flowinfoentry *pentry = NULL; 1037 struct sme_qos_cmdinfo cmd; 1038 enum sme_qos_statustype status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 1039 uint8_t tmask = 0; 1040 uint8_t new_tmask = 0; 1041 struct sme_qos_searchinfo search_key; 1042 QDF_STATUS hstatus; 1043 1044 sme_debug("invoked on session %d for flow %d", sessionId, QosFlowID); 1045 pSession = &sme_qos_cb.sessionInfo[sessionId]; 1046 /* if caller sent an empty TSPEC, fill up with the default one */ 1047 if (!pQoSInfo) { 1048 sme_warn("caller sent an empty QoS param list, using defaults"); 1049 /* find the AC with UPType passed in */ 1050 ac = sme_qos_up_to_ac(UPType); 1051 if (QCA_WLAN_AC_ALL == ac) { 1052 sme_err("invalid AC %d from UP %d", ac, UPType); 1053 1054 return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; 1055 } 1056 Tspec_Info = sme_qos_cb.def_QoSInfo[ac]; 1057 } else { 1058 /* find the AC */ 1059 ac = sme_qos_up_to_ac(pQoSInfo->ts_info.up); 1060 if (QCA_WLAN_AC_ALL == ac) { 1061 sme_err("invalid AC %d from UP %d", ac, 1062 pQoSInfo->ts_info.up); 1063 1064 return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; 1065 } 1066 /* validate QoS params */ 1067 if (!sme_qos_validate_requested_params(mac, pQoSInfo, 1068 sessionId)) { 1069 sme_err("invalid params"); 1070 return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; 1071 } 1072 Tspec_Info = *pQoSInfo; 1073 } 1074 pACInfo = &pSession->ac_info[ac]; 1075 /* check to consider the following flowing scenario. 1076 * Addts request is pending on one AC, while APSD requested on another 1077 * which needs a reassoc. Will buffer a request if Addts is pending 1078 * on any AC, which will safeguard the above scenario, & also won't 1079 * confuse PE with back to back Addts or Addts followed by Reassoc 1080 */ 1081 if (sme_qos_is_rsp_pending(sessionId, ac)) { 1082 sme_debug("buffering the setup request for flow %d in state %d since another request is pending", 1083 QosFlowID, pACInfo->curr_state); 1084 /* we need to buffer the command */ 1085 cmd.command = SME_QOS_SETUP_REQ; 1086 cmd.mac = mac; 1087 cmd.sessionId = sessionId; 1088 cmd.u.setupCmdInfo.HDDcontext = HDDcontext; 1089 cmd.u.setupCmdInfo.QoSInfo = Tspec_Info; 1090 cmd.u.setupCmdInfo.QoSCallback = QoSCallback; 1091 cmd.u.setupCmdInfo.UPType = UPType; 1092 cmd.u.setupCmdInfo.hoRenewal = hoRenewal; 1093 cmd.u.setupCmdInfo.QosFlowID = QosFlowID; 1094 hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); 1095 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 1096 sme_err("couldn't buffer the setup request in state = %d", 1097 pACInfo->curr_state); 1098 return SME_QOS_STATUS_SETUP_FAILURE_RSP; 1099 } 1100 sme_debug("Buffered setup request for flow = %d", QosFlowID); 1101 return SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; 1102 } 1103 /* get into the state m/c to see if the request can be granted */ 1104 switch (pACInfo->curr_state) { 1105 case SME_QOS_LINK_UP: 1106 /* call the internal qos setup logic to decide on if the 1107 * request is NOP, or need reassoc for APSD and/or need to 1108 * send out ADDTS 1109 */ 1110 status = sme_qos_setup(mac, sessionId, &Tspec_Info, ac); 1111 sme_debug("On session %d with AC %d in state SME_QOS_LINK_UP sme_qos_setup returned with status %d", 1112 sessionId, ac, status); 1113 1114 if ((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) || 1115 (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) 1116 || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == 1117 status)) { 1118 /* we received an expected "good" status */ 1119 /* create an entry in the flow list */ 1120 pentry = qdf_mem_malloc(sizeof(*pentry)); 1121 if (!pentry) 1122 return SME_QOS_STATUS_SETUP_FAILURE_RSP; 1123 1124 pentry->ac_type = ac; 1125 pentry->HDDcontext = HDDcontext; 1126 pentry->QoSCallback = QoSCallback; 1127 pentry->hoRenewal = hoRenewal; 1128 pentry->QosFlowID = QosFlowID; 1129 pentry->sessionId = sessionId; 1130 /* since we are in state SME_QOS_LINK_UP this must be 1131 * the first TSPEC on this AC, so use index 0 1132 * (mask bit 1) 1133 */ 1134 pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0] = 1135 Tspec_Info; 1136 if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { 1137 if (pACInfo->tspec_mask_status && 1138 !pACInfo->reassoc_pending) { 1139 sme_err("On session %d with AC %d in state SME_QOS_LINK_UP tspec_mask_status is %d but should not be set yet", 1140 sessionId, ac, 1141 pACInfo->tspec_mask_status); 1142 qdf_mem_free(pentry); 1143 return SME_QOS_STATUS_SETUP_FAILURE_RSP; 1144 } 1145 pACInfo->tspec_mask_status = 1146 SME_QOS_TSPEC_MASK_BIT_1_SET; 1147 if (!pACInfo->reassoc_pending) 1148 /* we didn't request for reassoc, it 1149 * must be a tspec negotiation 1150 */ 1151 pACInfo->tspec_pending = 1; 1152 1153 pentry->reason = SME_QOS_REASON_SETUP; 1154 new_state = SME_QOS_REQUESTED; 1155 } else { 1156 /* SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_ 1157 * RSP or SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET 1158 * _ALREADY 1159 */ 1160 pentry->reason = SME_QOS_REASON_REQ_SUCCESS; 1161 new_state = SME_QOS_QOS_ON; 1162 pACInfo->tspec_mask_status = 1163 SME_QOS_TSPEC_MASK_BIT_1_SET; 1164 pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = 1165 Tspec_Info; 1166 if (buffered_cmd && !pentry->hoRenewal) { 1167 QoSCallback(MAC_HANDLE(mac), 1168 HDDcontext, 1169 &pACInfo-> 1170 curr_QoSInfo 1171 [SME_QOS_TSPEC_INDEX_0], 1172 status, pentry->QosFlowID); 1173 } 1174 pentry->hoRenewal = false; 1175 } 1176 pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0]++; 1177 1178 /* indicate on which index the flow entry belongs to & 1179 * add it to the Flow List at the end 1180 */ 1181 pentry->tspec_mask = pACInfo->tspec_mask_status; 1182 pentry->QoSInfo = Tspec_Info; 1183 sme_debug("Creating entry on session %d at %pK with flowID %d", 1184 sessionId, pentry, QosFlowID); 1185 csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, 1186 true); 1187 } else { 1188 /* unexpected status returned by sme_qos_setup() */ 1189 sme_err("On session %d unexpected status %d returned by sme_qos_setup", 1190 sessionId, status); 1191 new_state = pACInfo->curr_state; 1192 if (buffered_cmd && hoRenewal) 1193 QoSCallback(MAC_HANDLE(mac), HDDcontext, 1194 &pACInfo-> 1195 curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], 1196 SME_QOS_STATUS_RELEASE_QOS_LOST_IND, 1197 QosFlowID); 1198 } 1199 break; 1200 case SME_QOS_HANDOFF: 1201 case SME_QOS_REQUESTED: 1202 sme_debug("Buffering setup request for flow %d in state = %d", 1203 QosFlowID, pACInfo->curr_state); 1204 /* buffer cmd */ 1205 cmd.command = SME_QOS_SETUP_REQ; 1206 cmd.mac = mac; 1207 cmd.sessionId = sessionId; 1208 cmd.u.setupCmdInfo.HDDcontext = HDDcontext; 1209 cmd.u.setupCmdInfo.QoSInfo = Tspec_Info; 1210 cmd.u.setupCmdInfo.QoSCallback = QoSCallback; 1211 cmd.u.setupCmdInfo.UPType = UPType; 1212 cmd.u.setupCmdInfo.hoRenewal = hoRenewal; 1213 cmd.u.setupCmdInfo.QosFlowID = QosFlowID; 1214 hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); 1215 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 1216 sme_err("On session %d couldn't buffer the setup request for flow %d in state = %d", 1217 sessionId, QosFlowID, pACInfo->curr_state); 1218 return SME_QOS_STATUS_SETUP_FAILURE_RSP; 1219 } 1220 status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; 1221 new_state = pACInfo->curr_state; 1222 break; 1223 case SME_QOS_QOS_ON: 1224 1225 /* check if multiple flows running on the ac */ 1226 if ((pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] > 0) || 1227 (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0)) { 1228 /* do we need to care about the case where APSD 1229 * needed on ACM = 0 below? 1230 */ 1231 if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(mac) || 1232 sme_qos_is_acm(mac, pSession->assocInfo.bss_desc, 1233 ac, NULL)) { 1234 sme_debug("tspec_mask_status = %d for AC = %d", 1235 pACInfo->tspec_mask_status, ac); 1236 if (!pACInfo->tspec_mask_status) { 1237 sme_err("tspec_mask_status can't be 0 for ac: %d in state: %d", 1238 ac, pACInfo->curr_state); 1239 return status; 1240 } 1241 /* Flow aggregation */ 1242 if (((pACInfo->tspec_mask_status > 0) && 1243 (pACInfo->tspec_mask_status <= 1244 SME_QOS_TSPEC_INDEX_MAX))) { 1245 /* Either of upstream, downstream or 1246 * bidirectional flows are present If 1247 * either of new stream or current 1248 * stream is for bidirecional, aggregate 1249 * the new stream with the current 1250 * streams present and send out 1251 * aggregated Tspec. 1252 */ 1253 if ((Tspec_Info.ts_info.direction == 1254 SME_QOS_WMM_TS_DIR_BOTH) 1255 || (pACInfo-> 1256 curr_QoSInfo[pACInfo-> 1257 tspec_mask_status - 1258 1].ts_info. 1259 direction == 1260 SME_QOS_WMM_TS_DIR_BOTH)) 1261 /* Aggregate the new stream with 1262 * the current stream(s). 1263 */ 1264 tmask = pACInfo-> 1265 tspec_mask_status; 1266 /* None of new stream or current 1267 * (aggregated) streams are for 1268 * bidirectional. Check if the new 1269 * stream direction matches the current 1270 * stream direction. 1271 */ 1272 else if (pACInfo-> 1273 curr_QoSInfo[pACInfo-> 1274 tspec_mask_status 1275 - 1276 1].ts_info. 1277 direction == 1278 Tspec_Info.ts_info.direction) 1279 /* Aggregate the new stream with 1280 * the current stream(s). 1281 */ 1282 tmask = 1283 pACInfo->tspec_mask_status; 1284 /* New stream is in different 1285 * direction. 1286 */ 1287 else { 1288 /* No Aggregation. Mark the 1289 * 2nd tpsec index also as 1290 * active. 1291 */ 1292 tmask = 1293 SME_QOS_TSPEC_MASK_CLEAR; 1294 new_tmask = 1295 SME_QOS_TSPEC_MASK_BIT_1_2_SET 1296 & ~pACInfo-> 1297 tspec_mask_status; 1298 pACInfo->tspec_mask_status = 1299 SME_QOS_TSPEC_MASK_BIT_1_2_SET; 1300 } 1301 } else if (SME_QOS_TSPEC_MASK_BIT_1_2_SET == 1302 pACInfo->tspec_mask_status) { 1303 /* Both uplink and downlink streams are 1304 * present. If new stream is 1305 * bidirectional, aggregate new stream 1306 * with all existing upstreams and down 1307 * streams. Send out new aggregated 1308 * tpsec. 1309 */ 1310 if (Tspec_Info.ts_info.direction == 1311 SME_QOS_WMM_TS_DIR_BOTH) { 1312 /* Only one tspec index (0) will 1313 * be in use after this 1314 * aggregation. 1315 */ 1316 tmask = 1317 SME_QOS_TSPEC_MASK_BIT_1_2_SET; 1318 pACInfo->tspec_mask_status = 1319 SME_QOS_TSPEC_MASK_BIT_1_SET; 1320 } 1321 /* New stream is also uni-directional 1322 * Find out the tsepc index with which 1323 * it needs to be aggregated 1324 */ 1325 else if (pACInfo-> 1326 curr_QoSInfo 1327 [SME_QOS_TSPEC_INDEX_0]. 1328 ts_info.direction != 1329 Tspec_Info.ts_info.direction) 1330 /* Aggregate with 2nd tspec 1331 * index 1332 */ 1333 tmask = 1334 SME_QOS_TSPEC_MASK_BIT_2_SET; 1335 else 1336 /* Aggregate with 1st tspec 1337 * index 1338 */ 1339 tmask = 1340 SME_QOS_TSPEC_MASK_BIT_1_SET; 1341 } else 1342 sme_debug("wrong tmask = %d", 1343 pACInfo->tspec_mask_status); 1344 } else 1345 /* ACM = 0 */ 1346 /* We won't be sending a TSPEC to the AP but 1347 * we still need to aggregate to calculate 1348 * trigger frame parameters 1349 */ 1350 tmask = SME_QOS_TSPEC_MASK_BIT_1_SET; 1351 1352 sme_debug("tmask = %d, new_tmask = %d in state = %d tspec_mask_status = %d for AC = %d", 1353 tmask, new_tmask, pACInfo->curr_state, 1354 pACInfo->tspec_mask_status, ac); 1355 if (tmask) { 1356 /* create the aggregate TSPEC */ 1357 if (tmask != SME_QOS_TSPEC_MASK_BIT_1_2_SET) { 1358 hstatus = 1359 sme_qos_aggregate_params( 1360 &Tspec_Info, 1361 &pACInfo-> 1362 curr_QoSInfo 1363 [tmask - 1], 1364 &pACInfo-> 1365 requested_QoSInfo 1366 [tmask - 1]); 1367 } else { 1368 /* Aggregate the new bidirectional 1369 * stream with the existing upstreams 1370 * and downstreams in tspec indices 0 1371 * and 1. 1372 */ 1373 tmask = SME_QOS_TSPEC_MASK_BIT_1_SET; 1374 1375 hstatus = sme_qos_aggregate_params( 1376 &Tspec_Info, &pACInfo-> 1377 curr_QoSInfo 1378 [SME_QOS_TSPEC_INDEX_0], 1379 &pACInfo-> 1380 requested_QoSInfo 1381 [tmask - 1]); 1382 if (hstatus == QDF_STATUS_SUCCESS) { 1383 hstatus = 1384 sme_qos_aggregate_params 1385 (&pACInfo-> 1386 curr_QoSInfo 1387 [SME_QOS_TSPEC_INDEX_1], 1388 &pACInfo-> 1389 requested_QoSInfo[tmask - 1], 1390 NULL); 1391 } 1392 } 1393 1394 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 1395 /* err msg */ 1396 sme_err("failed to aggregate params"); 1397 return SME_QOS_STATUS_SETUP_FAILURE_RSP; 1398 } 1399 } else { 1400 if (! 1401 (new_tmask > 0 1402 && new_tmask <= SME_QOS_TSPEC_INDEX_MAX)) { 1403 return SME_QOS_STATUS_SETUP_FAILURE_RSP; 1404 } 1405 tmask = new_tmask; 1406 pACInfo->requested_QoSInfo[tmask - 1] = 1407 Tspec_Info; 1408 } 1409 } else { 1410 sme_err("no flows running for ac = %d while in state = %d", 1411 ac, pACInfo->curr_state); 1412 return status; 1413 } 1414 /* although aggregating, make sure to request on the correct 1415 * UP,TID,PSB and direction 1416 */ 1417 pACInfo->requested_QoSInfo[tmask - 1].ts_info.up = 1418 Tspec_Info.ts_info.up; 1419 pACInfo->requested_QoSInfo[tmask - 1].ts_info.tid = 1420 Tspec_Info.ts_info.tid; 1421 pACInfo->requested_QoSInfo[tmask - 1].ts_info.direction = 1422 Tspec_Info.ts_info.direction; 1423 pACInfo->requested_QoSInfo[tmask - 1].ts_info.psb = 1424 Tspec_Info.ts_info.psb; 1425 status = 1426 sme_qos_setup(mac, sessionId, 1427 &pACInfo->requested_QoSInfo[tmask - 1], 1428 ac); 1429 sme_debug("On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", 1430 sessionId, ac, status); 1431 if ((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) || 1432 (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) 1433 || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == 1434 status)) { 1435 /* we received an expected "good" status */ 1436 /* create an entry in the flow list */ 1437 pentry = qdf_mem_malloc(sizeof(*pentry)); 1438 if (!pentry) 1439 return SME_QOS_STATUS_SETUP_FAILURE_RSP; 1440 1441 pentry->ac_type = ac; 1442 pentry->HDDcontext = HDDcontext; 1443 pentry->QoSCallback = QoSCallback; 1444 pentry->hoRenewal = hoRenewal; 1445 pentry->QosFlowID = QosFlowID; 1446 pentry->sessionId = sessionId; 1447 sme_debug("Creating flow %d", QosFlowID); 1448 if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == 1449 status) 1450 || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == 1451 status)) { 1452 new_state = pACInfo->curr_state; 1453 pentry->reason = SME_QOS_REASON_REQ_SUCCESS; 1454 pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = 1455 pACInfo-> 1456 requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]; 1457 if (buffered_cmd && !pentry->hoRenewal) { 1458 QoSCallback(MAC_HANDLE(mac), 1459 HDDcontext, 1460 &pACInfo-> 1461 curr_QoSInfo 1462 [SME_QOS_TSPEC_INDEX_0], 1463 status, pentry->QosFlowID); 1464 } 1465 if ( 1466 SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY 1467 == status) { 1468 /* if we are not in handoff, then notify 1469 * all flows on this AC that the 1470 * aggregate TSPEC may have changed 1471 */ 1472 if (!pentry->hoRenewal) { 1473 qdf_mem_zero(&search_key, 1474 sizeof 1475 (struct sme_qos_searchinfo)); 1476 search_key.key.ac_type = ac; 1477 search_key.index = 1478 SME_QOS_SEARCH_KEY_INDEX_2; 1479 search_key.sessionId = 1480 sessionId; 1481 hstatus = 1482 sme_qos_find_all_in_flow_list 1483 (mac, search_key, 1484 sme_qos_setup_fnp); 1485 if (!QDF_IS_STATUS_SUCCESS 1486 (hstatus)) { 1487 sme_err("couldn't notify other entries on this AC =%d", 1488 ac); 1489 } 1490 } 1491 } 1492 pentry->hoRenewal = false; 1493 } else { 1494 /* SME_QOS_STATUS_SETUP_REQ_PENDING_RSP */ 1495 new_state = SME_QOS_REQUESTED; 1496 pentry->reason = SME_QOS_REASON_SETUP; 1497 /* Need this info when addts comes back from PE 1498 * to know on which index of the AC the request 1499 * was from 1500 */ 1501 pACInfo->tspec_pending = tmask; 1502 } 1503 pACInfo->num_flows[tmask - 1]++; 1504 /* indicate on which index the flow entry belongs to & 1505 * add it to the Flow List at the end 1506 */ 1507 pentry->tspec_mask = tmask; 1508 pentry->QoSInfo = Tspec_Info; 1509 sme_debug("On session %d creating entry at %pK with flowID %d", 1510 sessionId, pentry, QosFlowID); 1511 csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, 1512 true); 1513 } else { 1514 /* unexpected status returned by sme_qos_setup() */ 1515 sme_err("On session %d unexpected status %d returned by sme_qos_setup", 1516 sessionId, status); 1517 new_state = pACInfo->curr_state; 1518 } 1519 break; 1520 case SME_QOS_CLOSED: 1521 case SME_QOS_INIT: 1522 default: 1523 sme_err("setup requested in unexpected state = %d", 1524 pACInfo->curr_state); 1525 new_state = pACInfo->curr_state; 1526 } 1527 /* If current state is same as previous no need for transition, 1528 * if we are doing reassoc & we are already in handoff state, no need to 1529 * move to requested state. But make sure to set the previous state as 1530 * requested state 1531 */ 1532 if ((new_state != pACInfo->curr_state) && 1533 (!(pACInfo->reassoc_pending && 1534 (SME_QOS_HANDOFF == pACInfo->curr_state)))) 1535 sme_qos_state_transition(sessionId, ac, new_state); 1536 1537 if (pACInfo->reassoc_pending && 1538 (SME_QOS_HANDOFF == pACInfo->curr_state)) 1539 pACInfo->prev_state = SME_QOS_REQUESTED; 1540 1541 if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) || 1542 (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)) 1543 (void)sme_qos_process_buffered_cmd(sessionId); 1544 1545 return status; 1546 } 1547 1548 /** 1549 * sme_qos_internal_modify_req() - The SME QoS internal function to request 1550 * for modification of certain QoS params on a flow running on a particular AC. 1551 * @mac: Pointer to the global MAC parameter structure. 1552 * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the 1553 * WMM TSPEC related info as defined above, provided by HDD 1554 * @QosFlowID: Identification per flow running on each AC generated by 1555 * SME. It is only meaningful if the QoS setup for the flow has 1556 * been successful already 1557 * 1558 * If the request involves admission control on the requested AC, HDD needs to 1559 * provide the necessary Traffic Specification (TSPEC) parameters & SME might 1560 * start the renegotiation process through ADDTS. 1561 * 1562 * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful. 1563 * Other status means request failed 1564 */ 1565 static enum sme_qos_statustype sme_qos_internal_modify_req(struct mac_context *mac, 1566 struct sme_qos_wmmtspecinfo *pQoSInfo, 1567 uint32_t QosFlowID, 1568 bool buffered_cmd) 1569 { 1570 tListElem *pEntry = NULL; 1571 struct sme_qos_sessioninfo *pSession; 1572 struct sme_qos_acinfo *pACInfo; 1573 struct sme_qos_flowinfoentry *pNewEntry = NULL; 1574 struct sme_qos_flowinfoentry *flow_info = NULL; 1575 enum qca_wlan_ac_type ac; 1576 enum sme_qos_states new_state = SME_QOS_CLOSED; 1577 enum sme_qos_statustype status = 1578 SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 1579 struct sme_qos_wmmtspecinfo Aggr_Tspec_Info; 1580 struct sme_qos_searchinfo search_key; 1581 struct sme_qos_cmdinfo cmd; 1582 uint8_t sessionId; 1583 QDF_STATUS hstatus; 1584 1585 sme_debug("invoked for flow %d", QosFlowID); 1586 1587 qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); 1588 /* set the key type & the key to be searched in the Flow List */ 1589 search_key.key.QosFlowID = QosFlowID; 1590 search_key.index = SME_QOS_SEARCH_KEY_INDEX_1; 1591 search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY; 1592 /* go through the link list to find out the details on the flow */ 1593 pEntry = sme_qos_find_in_flow_list(search_key); 1594 if (!pEntry) { 1595 /* Err msg */ 1596 sme_err("no match found for flowID = %d", QosFlowID); 1597 return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; 1598 } 1599 /* find the AC */ 1600 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); 1601 ac = flow_info->ac_type; 1602 1603 sessionId = flow_info->sessionId; 1604 pSession = &sme_qos_cb.sessionInfo[sessionId]; 1605 pACInfo = &pSession->ac_info[ac]; 1606 1607 /* validate QoS params */ 1608 if (!sme_qos_validate_requested_params(mac, pQoSInfo, sessionId)) { 1609 sme_err("invalid params"); 1610 return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; 1611 } 1612 /* For modify, make sure that direction, TID and UP are not 1613 * being altered 1614 */ 1615 if ((pQoSInfo->ts_info.direction != 1616 flow_info->QoSInfo.ts_info.direction) 1617 || (pQoSInfo->ts_info.up != flow_info->QoSInfo.ts_info.up) 1618 || (pQoSInfo->ts_info.tid != flow_info->QoSInfo.ts_info.tid)) { 1619 sme_err("Modification of direction/tid/up is not allowed"); 1620 1621 return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; 1622 } 1623 1624 /* should not be same as previous ioctl parameters */ 1625 if ((pQoSInfo->nominal_msdu_size == 1626 flow_info->QoSInfo.nominal_msdu_size) && 1627 (pQoSInfo->maximum_msdu_size == 1628 flow_info->QoSInfo.maximum_msdu_size) && 1629 (pQoSInfo->min_data_rate == 1630 flow_info->QoSInfo.min_data_rate) && 1631 (pQoSInfo->mean_data_rate == 1632 flow_info->QoSInfo.mean_data_rate) && 1633 (pQoSInfo->peak_data_rate == 1634 flow_info->QoSInfo.peak_data_rate) && 1635 (pQoSInfo->min_service_interval == 1636 flow_info->QoSInfo.min_service_interval) && 1637 (pQoSInfo->max_service_interval == 1638 flow_info->QoSInfo.max_service_interval) && 1639 (pQoSInfo->inactivity_interval == 1640 flow_info->QoSInfo.inactivity_interval) && 1641 (pQoSInfo->suspension_interval == 1642 flow_info->QoSInfo.suspension_interval) && 1643 (pQoSInfo->surplus_bw_allowance == 1644 flow_info->QoSInfo.surplus_bw_allowance)) { 1645 sme_debug("the addts parameters are same as last request, dropping the current request"); 1646 1647 return SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY; 1648 } 1649 1650 /* check to consider the following flowing scenario. 1651 * Addts request is pending on one AC, while APSD requested on another 1652 * which needs a reassoc. Will buffer a request if Addts is pending on 1653 * any AC, which will safeguard the above scenario, & also won't 1654 * confuse PE with back to back Addts or Addts followed by Reassoc 1655 */ 1656 if (sme_qos_is_rsp_pending(sessionId, ac)) { 1657 sme_debug("buffering the modify request for flow %d in state %d since another request is pending", 1658 QosFlowID, pACInfo->curr_state); 1659 /* we need to buffer the command */ 1660 cmd.command = SME_QOS_MODIFY_REQ; 1661 cmd.mac = mac; 1662 cmd.sessionId = sessionId; 1663 cmd.u.modifyCmdInfo.QosFlowID = QosFlowID; 1664 cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo; 1665 hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); 1666 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 1667 sme_err("couldn't buffer the modify request in state = %d", 1668 pACInfo->curr_state); 1669 return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 1670 } 1671 sme_debug("Buffered modify request for flow = %d", QosFlowID); 1672 return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; 1673 } 1674 /* get into the stat m/c to see if the request can be granted */ 1675 switch (pACInfo->curr_state) { 1676 case SME_QOS_QOS_ON: 1677 /* save the new params adding a new (duplicate) entry in the 1678 * Flow List Once we have decided on OTA exchange needed or 1679 * not we can delete the original one from the List 1680 */ 1681 pNewEntry = qdf_mem_malloc(sizeof(*pNewEntry)); 1682 if (!pNewEntry) 1683 return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 1684 1685 pNewEntry->ac_type = ac; 1686 pNewEntry->sessionId = sessionId; 1687 pNewEntry->HDDcontext = flow_info->HDDcontext; 1688 pNewEntry->QoSCallback = flow_info->QoSCallback; 1689 pNewEntry->QosFlowID = flow_info->QosFlowID; 1690 pNewEntry->reason = SME_QOS_REASON_MODIFY_PENDING; 1691 /* since it is a modify request, use the same index on which 1692 * the flow entry originally was running & add it to the Flow 1693 * List at the end 1694 */ 1695 pNewEntry->tspec_mask = flow_info->tspec_mask; 1696 pNewEntry->QoSInfo = *pQoSInfo; 1697 /* update the entry from Flow List which needed to be 1698 * modified 1699 */ 1700 flow_info->reason = SME_QOS_REASON_MODIFY; 1701 sme_debug("On session %d creating modified entry at %pK with flowID %d", 1702 sessionId, pNewEntry, pNewEntry->QosFlowID); 1703 /* add the new entry under construction to the Flow List */ 1704 csr_ll_insert_tail(&sme_qos_cb.flow_list, &pNewEntry->link, 1705 true); 1706 /* update TSPEC with the new param set */ 1707 hstatus = sme_qos_update_params(sessionId, 1708 ac, pNewEntry->tspec_mask, 1709 &Aggr_Tspec_Info); 1710 if (QDF_IS_STATUS_SUCCESS(hstatus)) { 1711 pACInfo->requested_QoSInfo[pNewEntry->tspec_mask - 1] = 1712 Aggr_Tspec_Info; 1713 /* if ACM, send out a new ADDTS */ 1714 status = sme_qos_setup(mac, sessionId, 1715 &pACInfo-> 1716 requested_QoSInfo[pNewEntry-> 1717 tspec_mask - 1], 1718 ac); 1719 sme_debug("On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", 1720 sessionId, ac, status); 1721 1722 if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { 1723 new_state = SME_QOS_REQUESTED; 1724 status = 1725 SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; 1726 pACInfo->tspec_pending = pNewEntry->tspec_mask; 1727 } else 1728 if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP 1729 == status) 1730 || 1731 (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY 1732 == status)) { 1733 new_state = SME_QOS_QOS_ON; 1734 1735 qdf_mem_zero(&search_key, 1736 sizeof(struct sme_qos_searchinfo)); 1737 /* delete the original entry in FLOW list which 1738 * got modified 1739 */ 1740 search_key.key.ac_type = ac; 1741 search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; 1742 search_key.sessionId = sessionId; 1743 hstatus = sme_qos_find_all_in_flow_list(mac, 1744 search_key, 1745 sme_qos_modify_fnp); 1746 if (!QDF_IS_STATUS_SUCCESS(hstatus)) 1747 status = 1748 SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 1749 1750 if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP != 1751 status) { 1752 pACInfo->curr_QoSInfo[pNewEntry-> 1753 tspec_mask - 1] = 1754 pACInfo-> 1755 requested_QoSInfo[pNewEntry-> 1756 tspec_mask - 1]; 1757 if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { 1758 status = 1759 SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY; 1760 qdf_mem_zero(&search_key, 1761 sizeof 1762 (struct sme_qos_searchinfo)); 1763 search_key.key.ac_type = ac; 1764 search_key.index = 1765 SME_QOS_SEARCH_KEY_INDEX_2; 1766 search_key.sessionId = 1767 sessionId; 1768 hstatus = 1769 sme_qos_find_all_in_flow_list 1770 (mac, search_key, 1771 sme_qos_modification_notify_fnp); 1772 if (!QDF_IS_STATUS_SUCCESS 1773 (hstatus)) { 1774 sme_err("couldn't notify other entries on this AC =%d", 1775 ac); 1776 } 1777 } else 1778 if 1779 (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP 1780 == status) 1781 status = 1782 SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP; 1783 } 1784 if (buffered_cmd) { 1785 flow_info->QoSCallback(MAC_HANDLE(mac), 1786 flow_info-> 1787 HDDcontext, 1788 &pACInfo-> 1789 curr_QoSInfo 1790 [pNewEntry-> 1791 tspec_mask - 1], 1792 status, 1793 flow_info-> 1794 QosFlowID); 1795 } 1796 1797 } else { 1798 /* unexpected status returned by 1799 * sme_qos_setup() 1800 */ 1801 sme_err("On session %d unexpected status %d returned by sme_qos_setup", 1802 sessionId, status); 1803 new_state = SME_QOS_QOS_ON; 1804 } 1805 } else { 1806 /* err msg */ 1807 sme_err("sme_qos_update_params() failed"); 1808 new_state = SME_QOS_LINK_UP; 1809 } 1810 /* if we are doing reassoc & we are already in handoff state, 1811 * no need to move to requested state. But make sure to set 1812 * the previous state as requested state 1813 */ 1814 if (!(pACInfo->reassoc_pending && 1815 (SME_QOS_HANDOFF == pACInfo->curr_state))) 1816 sme_qos_state_transition(sessionId, ac, new_state); 1817 else 1818 pACInfo->prev_state = SME_QOS_REQUESTED; 1819 break; 1820 case SME_QOS_HANDOFF: 1821 case SME_QOS_REQUESTED: 1822 sme_debug("Buffering modify request for flow %d in state = %d", 1823 QosFlowID, pACInfo->curr_state); 1824 /* buffer cmd */ 1825 cmd.command = SME_QOS_MODIFY_REQ; 1826 cmd.mac = mac; 1827 cmd.sessionId = sessionId; 1828 cmd.u.modifyCmdInfo.QosFlowID = QosFlowID; 1829 cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo; 1830 hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); 1831 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 1832 sme_err("couldn't buffer the modify request in state = %d", 1833 pACInfo->curr_state); 1834 return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 1835 } 1836 status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; 1837 break; 1838 case SME_QOS_CLOSED: 1839 case SME_QOS_INIT: 1840 case SME_QOS_LINK_UP: 1841 default: 1842 sme_err("modify requested in unexpected state = %d", 1843 pACInfo->curr_state); 1844 break; 1845 } 1846 if ((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) 1847 || (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == 1848 status)) 1849 (void)sme_qos_process_buffered_cmd(sessionId); 1850 1851 return status; 1852 } 1853 1854 /** 1855 * sme_qos_internal_release_req() - release QOS flow on a particular AC 1856 * @mac: Pointer to the global MAC parameter structure. 1857 * @sessionId: sessionId returned by sme_open_session. 1858 * @QosFlowID: Identification per flow running on each AC generated by SME 1859 * It is only meaningful if the QoS setup for the flow is successful 1860 * 1861 * The SME QoS internal function to request 1862 * for releasing a QoS flow running on a particular AC. 1863 1864 * Return: QDF_STATUS_SUCCESS - Release is successful. 1865 */ 1866 static enum sme_qos_statustype sme_qos_internal_release_req(struct mac_context *mac, 1867 uint8_t sessionId, 1868 uint32_t QosFlowID, 1869 bool buffered_cmd) 1870 { 1871 tListElem *pEntry = NULL; 1872 struct sme_qos_sessioninfo *pSession; 1873 struct sme_qos_acinfo *pACInfo; 1874 struct sme_qos_flowinfoentry *flow_info = NULL; 1875 struct sme_qos_flowinfoentry *pDeletedFlow = NULL; 1876 enum qca_wlan_ac_type ac; 1877 enum sme_qos_states new_state = SME_QOS_CLOSED; 1878 enum sme_qos_statustype status = SME_QOS_STATUS_RELEASE_FAILURE_RSP; 1879 struct sme_qos_wmmtspecinfo Aggr_Tspec_Info; 1880 struct sme_qos_searchinfo search_key; 1881 struct sme_qos_cmdinfo cmd; 1882 tCsrRoamModifyProfileFields modifyProfileFields; 1883 bool deltsIssued = false; 1884 QDF_STATUS hstatus; 1885 bool biDirectionalFlowsPresent = false; 1886 bool uplinkFlowsPresent = false; 1887 bool downlinkFlowsPresent = false; 1888 tListElem *pResult = NULL; 1889 mac_handle_t mac_hdl = MAC_HANDLE(mac); 1890 1891 sme_debug("invoked for flow %d", QosFlowID); 1892 1893 qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); 1894 /* set the key type & the key to be searched in the Flow List */ 1895 search_key.key.QosFlowID = QosFlowID; 1896 search_key.index = SME_QOS_SEARCH_KEY_INDEX_1; 1897 search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY; 1898 /* go through the link list to find out the details on the flow */ 1899 pEntry = sme_qos_find_in_flow_list(search_key); 1900 1901 if (!pEntry) { 1902 /* Err msg */ 1903 sme_err("no match found for flowID = %d", QosFlowID); 1904 1905 pSession = &sme_qos_cb.sessionInfo[sessionId]; 1906 if (!buffered_cmd && 1907 !csr_ll_is_list_empty(&pSession->bufferedCommandList, 1908 false)) { 1909 cmd.command = SME_QOS_RELEASE_REQ; 1910 cmd.mac = mac; 1911 cmd.sessionId = sessionId; 1912 cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; 1913 hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); 1914 if (QDF_IS_STATUS_SUCCESS(hstatus)) { 1915 sme_debug("Buffered release request for flow = %d", 1916 QosFlowID); 1917 return SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; 1918 } 1919 } 1920 return SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP; 1921 } 1922 /* find the AC */ 1923 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); 1924 ac = flow_info->ac_type; 1925 sessionId = flow_info->sessionId; 1926 1927 if (!CSR_IS_SESSION_VALID(mac, sessionId)) { 1928 sme_err("Session Id: %d is invalid", sessionId); 1929 return status; 1930 } 1931 1932 pSession = &sme_qos_cb.sessionInfo[sessionId]; 1933 pACInfo = &pSession->ac_info[ac]; 1934 /* check to consider the following flowing scenario. 1935 * Addts request is pending on one AC, while APSD requested on another 1936 * which needs a reassoc. Will buffer a request if Addts is pending on 1937 * any AC, which will safeguard the above scenario, & also won't 1938 * confuse PE with back to back Addts or Addts followed by Reassoc 1939 */ 1940 if (sme_qos_is_rsp_pending(sessionId, ac)) { 1941 sme_debug("buffering the release request for flow %d in state %d since another request is pending", 1942 QosFlowID, pACInfo->curr_state); 1943 /* we need to buffer the command */ 1944 cmd.command = SME_QOS_RELEASE_REQ; 1945 cmd.mac = mac; 1946 cmd.sessionId = sessionId; 1947 cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; 1948 hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); 1949 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 1950 sme_err("couldn't buffer the release request in state = %d", 1951 pACInfo->curr_state); 1952 return SME_QOS_STATUS_RELEASE_FAILURE_RSP; 1953 } 1954 sme_debug("Buffered release request for flow = %d", QosFlowID); 1955 return SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; 1956 } 1957 /* get into the stat m/c to see if the request can be granted */ 1958 switch (pACInfo->curr_state) { 1959 case SME_QOS_QOS_ON: 1960 sme_debug("tspec_mask_status = %d for AC = %d with entry tspec_mask = %d", 1961 pACInfo->tspec_mask_status, ac, 1962 flow_info->tspec_mask); 1963 1964 /* check if multiple flows running on the ac */ 1965 if (pACInfo->num_flows[flow_info->tspec_mask - 1] > 1) { 1966 /* don't want to include the flow in the new TSPEC on 1967 * which release is requested 1968 */ 1969 flow_info->reason = SME_QOS_REASON_RELEASE; 1970 1971 /* Check if the flow being released is for bi-diretional 1972 * Following flows may present in the system. 1973 * a) bi-directional flows 1974 * b) uplink flows 1975 * c) downlink flows. 1976 * If the flow being released is for bidirectional, 1977 * splitting of existing streams into two tspec indices 1978 * is required in case ff (b), (c) are present and not 1979 * (a). In case if split occurs, all upstreams are 1980 * aggregated into tspec index 0, downstreams are 1981 * aggregaed into tspec index 1 and two tspec requests 1982 * for (aggregated) upstream(s) followed by (aggregated) 1983 * downstream(s) is sent to AP. 1984 */ 1985 if (flow_info->QoSInfo.ts_info.direction == 1986 SME_QOS_WMM_TS_DIR_BOTH) { 1987 qdf_mem_zero(&search_key, 1988 sizeof(struct sme_qos_searchinfo)); 1989 /* set the key type & the key to be searched in 1990 * the Flow List 1991 */ 1992 search_key.key.ac_type = ac; 1993 search_key.index = SME_QOS_SEARCH_KEY_INDEX_4; 1994 search_key.sessionId = sessionId; 1995 search_key.direction = SME_QOS_WMM_TS_DIR_BOTH; 1996 pResult = sme_qos_find_in_flow_list(search_key); 1997 if (pResult) 1998 biDirectionalFlowsPresent = true; 1999 2000 if (!biDirectionalFlowsPresent) { 2001 /* The only existing bidirectional flow 2002 * is being released 2003 */ 2004 2005 /* Check if uplink flows exist */ 2006 search_key.direction = 2007 SME_QOS_WMM_TS_DIR_UPLINK; 2008 pResult = 2009 sme_qos_find_in_flow_list(search_key); 2010 if (pResult) 2011 uplinkFlowsPresent = true; 2012 2013 /* Check if downlink flows exist */ 2014 search_key.direction = 2015 SME_QOS_WMM_TS_DIR_DOWNLINK; 2016 pResult = 2017 sme_qos_find_in_flow_list(search_key); 2018 if (pResult) 2019 downlinkFlowsPresent = true; 2020 2021 if (uplinkFlowsPresent 2022 && downlinkFlowsPresent) { 2023 /* Need to split the uni- 2024 * directional flows into 2025 * SME_QOS_TSPEC_INDEX_0 and 2026 * SME_QOS_TSPEC_INDEX_1 2027 */ 2028 2029 qdf_mem_zero(&search_key, 2030 sizeof 2031 (struct sme_qos_searchinfo)); 2032 /* Mark all downstream flows as 2033 * using tspec index 1 2034 */ 2035 search_key.key.ac_type = ac; 2036 search_key.index = 2037 SME_QOS_SEARCH_KEY_INDEX_4; 2038 search_key.sessionId = 2039 sessionId; 2040 search_key.direction = 2041 SME_QOS_WMM_TS_DIR_DOWNLINK; 2042 sme_qos_update_tspec_mask 2043 (sessionId, search_key, 2044 SME_QOS_TSPEC_MASK_BIT_2_SET); 2045 2046 /* Aggregate all downstream 2047 * flows 2048 */ 2049 hstatus = 2050 sme_qos_update_params 2051 (sessionId, ac, 2052 SME_QOS_TSPEC_MASK_BIT_2_SET, 2053 &Aggr_Tspec_Info); 2054 2055 sme_err("On session %d buffering the AddTS request for AC %d in state %d as Addts is pending on other Tspec index of this AC", 2056 sessionId, ac, 2057 pACInfo->curr_state); 2058 2059 /* Buffer the (aggregated) tspec 2060 * request for downstream flows. 2061 * Please note that the 2062 * (aggregated) tspec for 2063 * upstream flows is sent out by 2064 * the susequent logic. 2065 */ 2066 cmd.command = 2067 SME_QOS_RESEND_REQ; 2068 cmd.mac = mac; 2069 cmd.sessionId = sessionId; 2070 cmd.u.resendCmdInfo.ac = ac; 2071 cmd.u.resendCmdInfo.tspecMask = 2072 SME_QOS_TSPEC_MASK_BIT_2_SET; 2073 cmd.u.resendCmdInfo.QoSInfo = 2074 Aggr_Tspec_Info; 2075 pACInfo-> 2076 requested_QoSInfo 2077 [SME_QOS_TSPEC_MASK_BIT_2_SET 2078 - 1] = Aggr_Tspec_Info; 2079 if (!QDF_IS_STATUS_SUCCESS 2080 (sme_qos_buffer_cmd 2081 (&cmd, 2082 false))) { 2083 sme_err("On session %d unable to buffer the AddTS request for AC %d TSPEC %d in state %d", 2084 sessionId, ac, 2085 SME_QOS_TSPEC_MASK_BIT_2_SET, 2086 pACInfo-> 2087 curr_state); 2088 2089 return 2090 SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 2091 } 2092 pACInfo->tspec_mask_status = 2093 SME_QOS_TSPEC_MASK_BIT_1_2_SET; 2094 2095 } 2096 } 2097 } 2098 2099 /* In case of splitting of existing streams, 2100 * tspec_mask will be pointing to tspec index 0 and 2101 * aggregated tspec for upstream(s) is sent out here. 2102 */ 2103 hstatus = sme_qos_update_params(sessionId, 2104 ac, flow_info->tspec_mask, 2105 &Aggr_Tspec_Info); 2106 if (QDF_IS_STATUS_SUCCESS(hstatus)) { 2107 pACInfo->requested_QoSInfo[flow_info-> 2108 tspec_mask - 1] = 2109 Aggr_Tspec_Info; 2110 /* if ACM, send out a new ADDTS */ 2111 status = sme_qos_setup(mac, sessionId, 2112 &pACInfo-> 2113 requested_QoSInfo 2114 [flow_info->tspec_mask - 2115 1], ac); 2116 sme_debug("On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", 2117 sessionId, ac, status); 2118 2119 if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == 2120 status) { 2121 new_state = SME_QOS_REQUESTED; 2122 status = 2123 SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; 2124 pACInfo->tspec_pending = 2125 flow_info->tspec_mask; 2126 } else 2127 if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)) { 2128 new_state = SME_QOS_QOS_ON; 2129 pACInfo->num_flows[flow_info-> 2130 tspec_mask - 1]--; 2131 pACInfo->curr_QoSInfo[flow_info-> 2132 tspec_mask - 1] = 2133 pACInfo-> 2134 requested_QoSInfo[flow_info-> 2135 tspec_mask - 1]; 2136 /* delete the entry from Flow List */ 2137 sme_debug("Deleting entry at %pK with flowID %d", 2138 flow_info, QosFlowID); 2139 csr_ll_remove_entry(&sme_qos_cb. 2140 flow_list, pEntry, true); 2141 pDeletedFlow = flow_info; 2142 if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { 2143 qdf_mem_zero(&search_key, 2144 sizeof 2145 (struct sme_qos_searchinfo)); 2146 search_key.key.ac_type = ac; 2147 search_key.index = 2148 SME_QOS_SEARCH_KEY_INDEX_2; 2149 search_key.sessionId = 2150 sessionId; 2151 hstatus = 2152 sme_qos_find_all_in_flow_list 2153 (mac, search_key, 2154 sme_qos_setup_fnp); 2155 if (!QDF_IS_STATUS_SUCCESS 2156 (hstatus)) { 2157 sme_err("couldn't notify other entries on this AC =%d", 2158 ac); 2159 } 2160 } 2161 status = 2162 SME_QOS_STATUS_RELEASE_SUCCESS_RSP; 2163 if (buffered_cmd) { 2164 flow_info->QoSCallback(MAC_HANDLE(mac), 2165 flow_info-> 2166 HDDcontext, 2167 &pACInfo-> 2168 curr_QoSInfo 2169 [flow_info-> 2170 tspec_mask - 1], 2171 status, 2172 flow_info-> 2173 QosFlowID); 2174 } 2175 } else { 2176 /* unexpected status returned by 2177 * sme_qos_setup() 2178 */ 2179 sme_err("On session %d unexpected status %d returned by sme_qos_setup", 2180 sessionId, status); 2181 new_state = SME_QOS_LINK_UP; 2182 pACInfo->num_flows[flow_info-> 2183 tspec_mask - 1]--; 2184 pACInfo->curr_QoSInfo[flow_info-> 2185 tspec_mask - 1] = 2186 pACInfo-> 2187 requested_QoSInfo[flow_info-> 2188 tspec_mask - 1]; 2189 /* delete the entry from Flow List */ 2190 sme_debug("On session %d deleting entry at %pK with flowID %d", 2191 sessionId, flow_info, 2192 QosFlowID); 2193 csr_ll_remove_entry(&sme_qos_cb. 2194 flow_list, 2195 pEntry, true); 2196 pDeletedFlow = flow_info; 2197 if (buffered_cmd) { 2198 flow_info->QoSCallback(MAC_HANDLE(mac), 2199 flow_info-> 2200 HDDcontext, 2201 &pACInfo-> 2202 curr_QoSInfo 2203 [flow_info-> 2204 tspec_mask - 1], 2205 status, 2206 flow_info-> 2207 QosFlowID); 2208 } 2209 } 2210 } else { 2211 /* err msg */ 2212 sme_err("sme_qos_update_params() failed"); 2213 new_state = SME_QOS_LINK_UP; 2214 if (buffered_cmd) { 2215 flow_info->QoSCallback(MAC_HANDLE(mac), 2216 flow_info-> 2217 HDDcontext, 2218 &pACInfo-> 2219 curr_QoSInfo 2220 [flow_info-> 2221 tspec_mask - 1], 2222 status, 2223 flow_info-> 2224 QosFlowID); 2225 } 2226 } 2227 } else { 2228 /* this is the only flow aggregated in this TSPEC */ 2229 status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP; 2230 /* check if delts needs to be sent */ 2231 if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(mac) || 2232 sme_qos_is_acm(mac, pSession->assocInfo.bss_desc, 2233 ac, NULL)) { 2234 /* check if other TSPEC for this AC is also 2235 * in use 2236 */ 2237 if (SME_QOS_TSPEC_MASK_BIT_1_2_SET != 2238 pACInfo->tspec_mask_status) { 2239 /* this is the only TSPEC active on this 2240 * AC so indicate that we no longer 2241 * require APSD 2242 */ 2243 pSession->apsdMask &= 2244 ~(1 << (QCA_WLAN_AC_VO - ac)); 2245 /* Also update modifyProfileFields. 2246 * uapsd_mask in CSR for consistency 2247 */ 2248 csr_get_modify_profile_fields(mac, 2249 flow_info-> 2250 sessionId, 2251 &modifyProfileFields); 2252 modifyProfileFields.uapsd_mask = 2253 pSession->apsdMask; 2254 csr_set_modify_profile_fields(mac, 2255 flow_info-> 2256 sessionId, 2257 &modifyProfileFields); 2258 if (!pSession->apsdMask) { 2259 /* this session no longer needs 2260 * UAPSD do any sessions still 2261 * require UAPSD? 2262 */ 2263 if (!sme_qos_is_uapsd_active()) 2264 /* No sessions require 2265 * UAPSD so turn it off 2266 * (really don't care 2267 * when PMC stops it) 2268 */ 2269 sme_ps_uapsd_disable( 2270 mac_hdl, 2271 sessionId); 2272 } 2273 } 2274 if (SME_QOS_RELEASE_DEFAULT == 2275 pACInfo->relTrig) { 2276 /* send delts */ 2277 hstatus = 2278 qos_issue_command(mac, 2279 sessionId, 2280 eSmeCommandDelTs, 2281 NULL, ac, 2282 flow_info-> 2283 tspec_mask); 2284 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 2285 /* err msg */ 2286 sme_err("sme_qos_del_ts_req() failed"); 2287 status = 2288 SME_QOS_STATUS_RELEASE_FAILURE_RSP; 2289 } else { 2290 pACInfo->tspec_mask_status &= 2291 SME_QOS_TSPEC_MASK_BIT_1_2_SET 2292 & (~flow_info->tspec_mask); 2293 deltsIssued = true; 2294 } 2295 } else { 2296 pACInfo->tspec_mask_status &= 2297 SME_QOS_TSPEC_MASK_BIT_1_2_SET & 2298 (~flow_info->tspec_mask); 2299 deltsIssued = true; 2300 } 2301 } else if (pSession->apsdMask & 2302 (1 << (QCA_WLAN_AC_VO - ac))) { 2303 /* reassoc logic */ 2304 csr_get_modify_profile_fields(mac, sessionId, 2305 &modifyProfileFields); 2306 modifyProfileFields.uapsd_mask |= 2307 pSession->apsdMask; 2308 modifyProfileFields.uapsd_mask &= 2309 ~(1 << (QCA_WLAN_AC_VO - ac)); 2310 pSession->apsdMask &= 2311 ~(1 << (QCA_WLAN_AC_VO - ac)); 2312 if (!pSession->apsdMask) { 2313 /* this session no longer needs UAPSD 2314 * do any sessions still require UAPSD? 2315 */ 2316 if (!sme_qos_is_uapsd_active()) 2317 /* No sessions require UAPSD so 2318 * turn it off (really don't 2319 * care when PMC stops it) 2320 */ 2321 sme_ps_uapsd_disable( 2322 mac_hdl, sessionId); 2323 } 2324 hstatus = sme_qos_request_reassoc(mac, 2325 sessionId, 2326 &modifyProfileFields, 2327 false); 2328 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 2329 /* err msg */ 2330 sme_err("Reassoc failed"); 2331 status = 2332 SME_QOS_STATUS_RELEASE_FAILURE_RSP; 2333 } else { 2334 /* no need to wait */ 2335 pACInfo->reassoc_pending = false; 2336 pACInfo->prev_state = SME_QOS_LINK_UP; 2337 pACInfo->tspec_pending = 0; 2338 } 2339 } else { 2340 sme_debug("nothing to do for AC = %d", ac); 2341 } 2342 2343 if (SME_QOS_RELEASE_BY_AP == pACInfo->relTrig) { 2344 flow_info->QoSCallback(MAC_HANDLE(mac), 2345 flow_info->HDDcontext, 2346 &pACInfo-> 2347 curr_QoSInfo[flow_info-> 2348 tspec_mask - 2349 1], 2350 SME_QOS_STATUS_RELEASE_QOS_LOST_IND, 2351 flow_info->QosFlowID); 2352 2353 sme_debug("Deleting entry at %pK with flowID %d", 2354 flow_info, flow_info->QosFlowID); 2355 } else if (buffered_cmd) { 2356 flow_info->QoSCallback(MAC_HANDLE(mac), 2357 flow_info->HDDcontext, 2358 NULL, status, 2359 flow_info->QosFlowID); 2360 } 2361 2362 if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == status) 2363 break; 2364 2365 if (((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info-> 2366 tspec_mask) > 0) 2367 && 2368 ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info-> 2369 tspec_mask) <= SME_QOS_TSPEC_INDEX_MAX)) { 2370 if (pACInfo-> 2371 num_flows[(SME_QOS_TSPEC_MASK_BIT_1_2_SET & 2372 ~flow_info->tspec_mask) - 1] > 2373 0) 2374 new_state = SME_QOS_QOS_ON; 2375 else 2376 new_state = SME_QOS_LINK_UP; 2377 } else { 2378 sme_debug("Exceeded the array bounds of pACInfo->num_flows"); 2379 return 2380 SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP; 2381 } 2382 2383 if (false == deltsIssued) { 2384 qdf_mem_zero(&pACInfo-> 2385 curr_QoSInfo[flow_info-> 2386 tspec_mask - 1], 2387 sizeof(struct sme_qos_wmmtspecinfo)); 2388 } 2389 qdf_mem_zero(&pACInfo-> 2390 requested_QoSInfo[flow_info->tspec_mask - 2391 1], 2392 sizeof(struct sme_qos_wmmtspecinfo)); 2393 pACInfo->num_flows[flow_info->tspec_mask - 1]--; 2394 /* delete the entry from Flow List */ 2395 sme_debug("On session %d deleting entry at %pK with flowID %d", 2396 sessionId, flow_info, QosFlowID); 2397 csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, 2398 true); 2399 pDeletedFlow = flow_info; 2400 pACInfo->relTrig = SME_QOS_RELEASE_DEFAULT; 2401 } 2402 /* if we are doing reassoc & we are already in handoff state, no 2403 * need to move to requested state. But make sure to set the 2404 * previous state as requested state 2405 */ 2406 if (SME_QOS_HANDOFF != pACInfo->curr_state) 2407 sme_qos_state_transition(sessionId, ac, new_state); 2408 2409 if (pACInfo->reassoc_pending) 2410 pACInfo->prev_state = SME_QOS_REQUESTED; 2411 break; 2412 case SME_QOS_HANDOFF: 2413 case SME_QOS_REQUESTED: 2414 /* buffer cmd */ 2415 cmd.command = SME_QOS_RELEASE_REQ; 2416 cmd.mac = mac; 2417 cmd.sessionId = sessionId; 2418 cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; 2419 hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); 2420 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 2421 sme_err("couldn't buffer the release request in state = %d", 2422 pACInfo->curr_state); 2423 return SME_QOS_STATUS_RELEASE_FAILURE_RSP; 2424 } 2425 status = SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; 2426 break; 2427 case SME_QOS_CLOSED: 2428 case SME_QOS_INIT: 2429 case SME_QOS_LINK_UP: 2430 default: 2431 /* print error msg */ 2432 sme_err("release request in unexpected state = %d", 2433 pACInfo->curr_state); 2434 break; 2435 } 2436 /* if we deleted a flow, reclaim the memory */ 2437 if (pDeletedFlow) 2438 qdf_mem_free(pDeletedFlow); 2439 2440 if (SME_QOS_STATUS_RELEASE_SUCCESS_RSP == status) 2441 (void)sme_qos_process_buffered_cmd(sessionId); 2442 2443 return status; 2444 } 2445 2446 /** 2447 * sme_qos_setup() - internal SME QOS setup function. 2448 * @mac: Pointer to the global MAC parameter structure. 2449 * @sessionId: Session upon which setup is being performed 2450 * @pTspec_Info: Pointer to struct sme_qos_wmmtspecinfo which contains the WMM 2451 * TSPEC related info as defined above 2452 * @ac: Enumeration of the various EDCA Access Categories. 2453 * 2454 * The internal qos setup function which has the intelligence 2455 * if the request is NOP, or for APSD and/or need to send out ADDTS. 2456 * It also does the sanity check for QAP, AP supports APSD etc. 2457 * The logic used in the code might be confusing. 2458 * 2459 * Trying to cover all the cases here. 2460 * AP supports App wants ACM = 1 Already set APSD Result 2461 * | 0 | 0 | 0 | 0 | NO ACM NO APSD 2462 * | 0 | 0 | 0 | 1 | NO ACM NO APSD/INVALID 2463 * | 0 | 0 | 1 | 0 | ADDTS 2464 * | 0 | 0 | 1 | 1 | ADDTS 2465 * | 0 | 1 | 0 | 0 | FAILURE 2466 * | 0 | 1 | 0 | 1 | INVALID 2467 * | 0 | 1 | 1 | 0 | ADDTS 2468 * | 0 | 1 | 1 | 1 | ADDTS 2469 * | 1 | 0 | 0 | 0 | NO ACM NO APSD 2470 * | 1 | 0 | 0 | 1 | NO ACM NO APSD 2471 * | 1 | 0 | 1 | 0 | ADDTS 2472 * | 1 | 0 | 1 | 1 | ADDTS 2473 * | 1 | 1 | 0 | 0 | REASSOC 2474 * | 1 | 1 | 0 | 1 | NOP: APSD SET ALREADY 2475 * | 1 | 1 | 1 | 0 | ADDTS 2476 * | 1 | 1 | 1 | 1 | ADDTS 2477 * 2478 * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP if the setup is successful' 2479 */ 2480 static enum sme_qos_statustype sme_qos_setup(struct mac_context *mac, 2481 uint8_t sessionId, 2482 struct sme_qos_wmmtspecinfo *pTspec_Info, 2483 enum qca_wlan_ac_type ac) 2484 { 2485 struct sme_qos_sessioninfo *pSession; 2486 struct sme_qos_acinfo *pACInfo; 2487 enum sme_qos_statustype status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 2488 tDot11fBeaconIEs *pIes = NULL; 2489 tCsrRoamModifyProfileFields modifyProfileFields; 2490 QDF_STATUS hstatus; 2491 2492 if (!CSR_IS_SESSION_VALID(mac, sessionId)) { 2493 sme_err("Session Id %d is invalid", sessionId); 2494 return status; 2495 } 2496 pSession = &sme_qos_cb.sessionInfo[sessionId]; 2497 if (!pSession->sessionActive) { 2498 sme_err("Session %d is inactive", sessionId); 2499 return status; 2500 } 2501 if (!pSession->assocInfo.bss_desc) { 2502 sme_err("Session %d has an Invalid BSS Descriptor", sessionId); 2503 return status; 2504 } 2505 hstatus = csr_get_parsed_bss_description_ies(mac, 2506 pSession->assocInfo.bss_desc, 2507 &pIes); 2508 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 2509 sme_err("On session %d unable to parse BSS IEs", sessionId); 2510 return status; 2511 } 2512 2513 /* success so pIes was allocated */ 2514 2515 if (!CSR_IS_QOS_BSS(pIes)) { 2516 sme_err("On session %d AP doesn't support QoS", sessionId); 2517 qdf_mem_free(pIes); 2518 /* notify HDD through the synchronous status msg */ 2519 return SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP; 2520 } 2521 2522 sme_debug("UAPSD/PSB set %d: ", pTspec_Info->ts_info.psb); 2523 2524 pACInfo = &pSession->ac_info[ac]; 2525 do { 2526 /* is ACM enabled for this AC? */ 2527 if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(mac) || 2528 sme_qos_is_acm(mac, pSession->assocInfo.bss_desc, 2529 ac, NULL)) { 2530 /* ACM is enabled for this AC so we must send an 2531 * AddTS 2532 */ 2533 if (pTspec_Info->ts_info.psb && 2534 !(pIes->WMMParams. 2535 qosInfo & SME_QOS_AP_SUPPORTS_APSD) 2536 && !(pIes->WMMInfoAp.uapsd)) { 2537 /* application is looking for APSD but AP 2538 * doesn't support it 2539 */ 2540 sme_err("On session %d AP doesn't support APSD", 2541 sessionId); 2542 break; 2543 } 2544 2545 if (SME_QOS_MAX_TID == pTspec_Info->ts_info.tid) { 2546 /* App didn't set TID, generate one */ 2547 pTspec_Info->ts_info.tid = 2548 (uint8_t) (SME_QOS_WMM_UP_NC - 2549 pTspec_Info->ts_info.up); 2550 } 2551 /* addts logic */ 2552 hstatus = 2553 qos_issue_command(mac, sessionId, 2554 eSmeCommandAddTs, 2555 pTspec_Info, ac, 0); 2556 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 2557 sme_err("sme_qos_add_ts_req() failed"); 2558 break; 2559 } 2560 sme_debug("On session %d AddTS on AC %d is pending", 2561 sessionId, ac); 2562 status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; 2563 break; 2564 } 2565 /* ACM is not enabled for this AC */ 2566 /* Is the application looking for APSD? */ 2567 if (0 == pTspec_Info->ts_info.psb) { 2568 /* no, we don't need APSD but check the case, if the 2569 * setup is called as a result of a release or modify 2570 * which boils down to the fact that APSD was set on 2571 * this AC but no longer needed - so we need a reassoc 2572 * for the above case to let the AP know 2573 */ 2574 if (pSession-> 2575 apsdMask & (1 << (QCA_WLAN_AC_VO - ac))) { 2576 /* APSD was formerly enabled on this AC but is 2577 * no longer required so we must reassociate 2578 */ 2579 sme_debug("On session %d reassoc needed to disable APSD on AC %d", 2580 sessionId, ac); 2581 csr_get_modify_profile_fields(mac, sessionId, 2582 &modifyProfileFields); 2583 modifyProfileFields.uapsd_mask |= 2584 pSession->apsdMask; 2585 modifyProfileFields.uapsd_mask &= 2586 ~(1 << (QCA_WLAN_AC_VO - ac)); 2587 hstatus = 2588 sme_qos_request_reassoc(mac, sessionId, 2589 &modifyProfileFields, 2590 false); 2591 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 2592 /* err msg */ 2593 sme_err("Unable to request reassociation"); 2594 break; 2595 } else { 2596 sme_debug("On session %d reassociation to enable APSD on AC %d is pending", 2597 sessionId, ac); 2598 status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; 2599 pACInfo->reassoc_pending = true; 2600 } 2601 } else { 2602 /* we don't need APSD on this AC and we don't 2603 * currently have APSD on this AC 2604 */ 2605 sme_debug("Request is not looking for APSD & Admission Control isn't mandatory for the AC"); 2606 /* return success right away */ 2607 status = 2608 SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP; 2609 } 2610 break; 2611 } else if (!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) 2612 && !(pIes->WMMInfoAp.uapsd)) { 2613 /* application is looking for APSD but AP doesn't 2614 * support it 2615 */ 2616 sme_err("On session %d AP doesn't support APSD", 2617 sessionId); 2618 break; 2619 } else if (pSession-> 2620 apsdMask & (1 << (QCA_WLAN_AC_VO - ac))) { 2621 /* application is looking for APSD */ 2622 /* and it is already enabled on this AC */ 2623 status = SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY; 2624 sme_debug("Request is looking for APSD and it is already set for the AC"); 2625 break; 2626 } else { 2627 /* application is looking for APSD but it is not enabled on this 2628 * AC so we need to reassociate 2629 */ 2630 sme_debug("On session %d reassoc needed to enable APSD on AC %d", 2631 sessionId, ac); 2632 /* reassoc logic */ 2633 /* update the UAPSD mask to include the new */ 2634 /* AC on which APSD is requested */ 2635 csr_get_modify_profile_fields(mac, sessionId, 2636 &modifyProfileFields); 2637 modifyProfileFields.uapsd_mask |= 2638 pSession->apsdMask; 2639 modifyProfileFields.uapsd_mask |= 2640 1 << (QCA_WLAN_AC_VO - ac); 2641 hstatus = sme_qos_request_reassoc(mac, sessionId, 2642 &modifyProfileFields, 2643 false); 2644 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 2645 /* err msg */ 2646 sme_err("Unable to request reassociation"); 2647 break; 2648 } else { 2649 sme_debug("On session %d reassociation to enable APSD on AC %d is pending", 2650 sessionId, ac); 2651 status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; 2652 pACInfo->reassoc_pending = true; 2653 } 2654 } 2655 } while (0); 2656 2657 qdf_mem_free(pIes); 2658 return status; 2659 } 2660 2661 /* This is a dummy function now. But the purpose of me adding this was to 2662 * delay the TSPEC processing till SET_KEY completes. This function can be 2663 * used to do any SME_QOS processing after the SET_KEY. As of now, it is 2664 * not required as we are ok with tspec getting programmed before set_key 2665 * as the roam timings are measured without tspec in reassoc! 2666 */ 2667 static QDF_STATUS sme_qos_process_set_key_success_ind(struct mac_context *mac, 2668 uint8_t sessionId, void *pEvent_info) 2669 { 2670 (void)sme_qos_process_buffered_cmd(sessionId); 2671 2672 return QDF_STATUS_SUCCESS; 2673 } 2674 2675 #ifdef FEATURE_WLAN_ESE 2676 /** 2677 * sme_qos_ese_save_tspec_response() - save TSPEC parameters. 2678 * @mac: Pointer to the global MAC parameter structure. 2679 * @sessionId: SME session ID 2680 * @pTspec: Pointer to the TSPEC IE from the reassoc rsp 2681 * @ac: Access Category for which this TSPEC rsp is received 2682 * @tspecIndex: flow/direction 2683 * 2684 * This function saves the TSPEC parameters that came along in the TSPEC IE 2685 * in the reassoc response 2686 * 2687 * Return: QDF_STATUS_SUCCESS - Release is successful. 2688 */ 2689 static QDF_STATUS 2690 sme_qos_ese_save_tspec_response(struct mac_context *mac, uint8_t sessionId, 2691 tDot11fIEWMMTSPEC *pTspec, uint8_t ac, 2692 uint8_t tspecIndex) 2693 { 2694 tpSirAddtsRsp pAddtsRsp = 2695 &sme_qos_cb.sessionInfo[sessionId].ac_info[ac]. 2696 addTsRsp[tspecIndex]; 2697 2698 ac = sme_qos_up_to_ac_map[pTspec->user_priority]; 2699 2700 qdf_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp)); 2701 2702 pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP; 2703 pAddtsRsp->length = sizeof(tSirAddtsRsp); 2704 pAddtsRsp->rc = QDF_STATUS_SUCCESS; 2705 pAddtsRsp->sessionId = sessionId; 2706 pAddtsRsp->rsp.dialogToken = 0; 2707 pAddtsRsp->rsp.status = STATUS_SUCCESS; 2708 pAddtsRsp->rsp.wmeTspecPresent = pTspec->present; 2709 sme_debug("Copy Tspec to local data structure ac=%d, tspecIdx=%d", 2710 ac, tspecIndex); 2711 2712 if (pAddtsRsp->rsp.wmeTspecPresent) 2713 /* Copy TSPEC params received in assoc response to addts 2714 * response 2715 */ 2716 convert_wmmtspec(mac, &pAddtsRsp->rsp.tspec, pTspec); 2717 2718 return QDF_STATUS_SUCCESS; 2719 } 2720 2721 /** 2722 * sme_qos_ese_process_reassoc_tspec_rsp() - process ese reassoc tspec response 2723 * @mac: Pointer to the global MAC parameter structure. 2724 * @sessionId: SME session ID 2725 * @pEven_info: Pointer to the smeJoinRsp structure 2726 * 2727 * This function processes the WMM TSPEC IE in the reassoc response. 2728 * Reassoc triggered as part of ESE roaming to another ESE capable AP. 2729 * If the TSPEC was added before reassoc, as part of Call Admission Control, 2730 * the reasso req from the STA would carry the TSPEC parameters which were 2731 * already negotiated with the older AP. 2732 * 2733 * Return: QDF_STATUS_SUCCESS - Release is successful. 2734 */ 2735 static 2736 QDF_STATUS sme_qos_ese_process_reassoc_tspec_rsp(struct mac_context *mac, 2737 uint8_t sessionId, 2738 void *pEvent_info) 2739 { 2740 struct sme_qos_sessioninfo *pSession; 2741 struct sme_qos_acinfo *pACInfo; 2742 tDot11fIEWMMTSPEC *pTspecIE = NULL; 2743 struct csr_roam_session *pCsrSession = NULL; 2744 struct csr_roam_connectedinfo *pCsrConnectedInfo = NULL; 2745 QDF_STATUS status = QDF_STATUS_E_FAILURE; 2746 uint8_t ac, numTspec, cnt; 2747 uint8_t tspec_flow_index, tspec_mask_status; 2748 uint32_t tspecIeLen; 2749 2750 pCsrSession = CSR_GET_SESSION(mac, sessionId); 2751 if (!pCsrSession) { 2752 sme_err("session %d not found", sessionId); 2753 return QDF_STATUS_E_FAILURE; 2754 } 2755 pCsrConnectedInfo = &pCsrSession->connectedInfo; 2756 pSession = &sme_qos_cb.sessionInfo[sessionId]; 2757 2758 /* Get the TSPEC IEs which came along with the reassoc response */ 2759 /* from the pbFrames pointer */ 2760 pTspecIE = 2761 (tDot11fIEWMMTSPEC *) (pCsrConnectedInfo->pbFrames + 2762 pCsrConnectedInfo->nBeaconLength + 2763 pCsrConnectedInfo->nAssocReqLength + 2764 pCsrConnectedInfo->nAssocRspLength + 2765 pCsrConnectedInfo->nRICRspLength); 2766 2767 /* Get the number of tspecs Ies in the frame, the min length */ 2768 /* should be atleast equal to the one TSPEC IE */ 2769 tspecIeLen = pCsrConnectedInfo->nTspecIeLength; 2770 if (tspecIeLen < sizeof(tDot11fIEWMMTSPEC)) { 2771 sme_err("ESE Tspec IE len %d less than min %zu", 2772 tspecIeLen, sizeof(tDot11fIEWMMTSPEC)); 2773 return QDF_STATUS_E_FAILURE; 2774 } 2775 2776 sme_warn("TspecLen = %d, pbFrames = %pK, pTspecIE = %pK", 2777 tspecIeLen, pCsrConnectedInfo->pbFrames, pTspecIE); 2778 2779 numTspec = (tspecIeLen) / sizeof(tDot11fIEWMMTSPEC); 2780 for (cnt = 0; cnt < numTspec; cnt++) { 2781 ac = sme_qos_up_to_ac(pTspecIE->user_priority); 2782 if (ac >= QCA_WLAN_AC_ALL) { 2783 sme_err("ac %d more than it`s max value", ac); 2784 return QDF_STATUS_E_FAILURE; 2785 } 2786 pACInfo = &pSession->ac_info[ac]; 2787 tspec_mask_status = pACInfo->tspec_mask_status; 2788 sme_warn("UP=%d, ac=%d, tspec_mask_status=%x", 2789 pTspecIE->user_priority, ac, tspec_mask_status); 2790 2791 for (tspec_flow_index = 0; 2792 tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; 2793 tspec_flow_index++) { 2794 if (tspec_mask_status & (1 << tspec_flow_index)) { 2795 sme_warn("Found Tspec entry flow = %d AC = %d", 2796 tspec_flow_index, ac); 2797 sme_qos_ese_save_tspec_response(mac, sessionId, 2798 pTspecIE, ac, 2799 tspec_flow_index); 2800 } else { 2801 sme_warn("Not found Tspec entry flow = %d AC = %d", 2802 tspec_flow_index, ac); 2803 } 2804 } 2805 /* Increment the pointer to point it to the next TSPEC IE */ 2806 pTspecIE++; 2807 } 2808 2809 /* Send the Aggregated QoS request to HAL */ 2810 status = sme_qos_ft_aggr_qos_req(mac, sessionId); 2811 2812 return status; 2813 } 2814 2815 /** 2816 * sme_qos_copy_tspec_info() - copy tspec info. 2817 * @mac: Pointer to the global MAC parameter structure. 2818 * @pTspec_Info: source structure 2819 * @pTspec: destination structure 2820 * 2821 * This function copies the existing TSPEC parameters from the source structure 2822 * to the destination structure. 2823 * 2824 * Return: None 2825 */ 2826 static void sme_qos_copy_tspec_info(struct mac_context *mac, 2827 struct sme_qos_wmmtspecinfo *pTspec_Info, 2828 struct mac_tspec_ie *pTspec) 2829 { 2830 /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum 2831 * Service Interval, Service Start Time, Suspension Interval and Delay 2832 * Bound are all intended for HCCA operation and therefore must be set 2833 * to zero 2834 */ 2835 pTspec->delayBound = pTspec_Info->delay_bound; 2836 pTspec->inactInterval = pTspec_Info->inactivity_interval; 2837 pTspec->length = SME_QOS_TSPEC_IE_LENGTH; 2838 pTspec->maxBurstSz = pTspec_Info->max_burst_size; 2839 pTspec->maxMsduSz = pTspec_Info->maximum_msdu_size; 2840 pTspec->maxSvcInterval = pTspec_Info->max_service_interval; 2841 pTspec->meanDataRate = pTspec_Info->mean_data_rate; 2842 pTspec->mediumTime = pTspec_Info->medium_time; 2843 pTspec->minDataRate = pTspec_Info->min_data_rate; 2844 pTspec->minPhyRate = pTspec_Info->min_phy_rate; 2845 pTspec->minSvcInterval = pTspec_Info->min_service_interval; 2846 pTspec->nomMsduSz = pTspec_Info->nominal_msdu_size; 2847 pTspec->peakDataRate = pTspec_Info->peak_data_rate; 2848 pTspec->surplusBw = pTspec_Info->surplus_bw_allowance; 2849 pTspec->suspendInterval = pTspec_Info->suspension_interval; 2850 pTspec->svcStartTime = pTspec_Info->svc_start_time; 2851 pTspec->tsinfo.traffic.direction = pTspec_Info->ts_info.direction; 2852 2853 /* Make sure UAPSD is allowed */ 2854 if (pTspec_Info->ts_info.psb) 2855 pTspec->tsinfo.traffic.psb = pTspec_Info->ts_info.psb; 2856 else { 2857 pTspec->tsinfo.traffic.psb = 0; 2858 pTspec_Info->ts_info.psb = 0; 2859 } 2860 pTspec->tsinfo.traffic.tsid = pTspec_Info->ts_info.tid; 2861 pTspec->tsinfo.traffic.userPrio = pTspec_Info->ts_info.up; 2862 pTspec->tsinfo.traffic.accessPolicy = SME_QOS_ACCESS_POLICY_EDCA; 2863 pTspec->tsinfo.traffic.burstSizeDefn = 2864 pTspec_Info->ts_info.burst_size_defn; 2865 pTspec->tsinfo.traffic.ackPolicy = pTspec_Info->ts_info.ack_policy; 2866 pTspec->type = SME_QOS_TSPEC_IE_TYPE; 2867 2868 sme_debug("up = %d, tid = %d", pTspec_Info->ts_info.up, 2869 pTspec_Info->ts_info.tid); 2870 } 2871 2872 /** 2873 * sme_qos_ese_retrieve_tspec_info() - retrieve tspec info. 2874 * @mac: Pointer to the global MAC parameter structure. 2875 * @sessionId: SME session ID 2876 * @pTspecInfo: Pointer to the structure to carry back the TSPEC parameters 2877 * 2878 * This function is called by CSR when try to create reassoc request message to 2879 * PE - csrSendSmeReassocReqMsg. This functions get the existing tspec 2880 * parameters to be included in the reassoc request. 2881 * 2882 * Return: uint8_t - number of existing negotiated TSPECs 2883 */ 2884 uint8_t sme_qos_ese_retrieve_tspec_info(struct mac_context *mac_ctx, 2885 uint8_t session_id, tTspecInfo *tspec_info) 2886 { 2887 struct sme_qos_sessioninfo *session; 2888 struct sme_qos_acinfo *ac_info; 2889 uint8_t ac, num_tspec = 0; 2890 tTspecInfo *dst_tspec = tspec_info; 2891 uint8_t tspec_mask; 2892 uint8_t tspec_pending; 2893 2894 /* TODO: Check if TSPEC has already been established 2895 * if not return 2896 */ 2897 session = &sme_qos_cb.sessionInfo[session_id]; 2898 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 2899 volatile uint8_t index = 0; 2900 2901 ac_info = &session->ac_info[ac]; 2902 tspec_pending = ac_info->tspec_pending; 2903 tspec_mask = ac_info->tspec_mask_status; 2904 do { 2905 /* 2906 * If a tspec status is pending, take 2907 * requested_QoSInfo for RIC request, 2908 * else use curr_QoSInfo for the 2909 * RIC request 2910 */ 2911 if ((tspec_mask & SME_QOS_TSPEC_MASK_BIT_1_SET) 2912 && (tspec_pending & 2913 SME_QOS_TSPEC_MASK_BIT_1_SET)){ 2914 sme_qos_copy_tspec_info(mac_ctx, 2915 &ac_info->requested_QoSInfo[index], 2916 &dst_tspec->tspec); 2917 dst_tspec->valid = true; 2918 num_tspec++; 2919 dst_tspec++; 2920 } else if ((tspec_mask & SME_QOS_TSPEC_MASK_BIT_1_SET) 2921 && !(tspec_pending & 2922 SME_QOS_TSPEC_MASK_BIT_1_SET)){ 2923 sme_qos_copy_tspec_info(mac_ctx, 2924 &ac_info->curr_QoSInfo[index], 2925 &dst_tspec->tspec); 2926 dst_tspec->valid = true; 2927 num_tspec++; 2928 dst_tspec++; 2929 } 2930 tspec_mask >>= 1; 2931 tspec_pending >>= 1; 2932 index++; 2933 } while (tspec_mask); 2934 } 2935 return num_tspec; 2936 } 2937 2938 #endif 2939 2940 #ifdef WLAN_FEATURE_HOST_ROAM 2941 static 2942 QDF_STATUS sme_qos_create_tspec_ricie(struct mac_context *mac, 2943 struct sme_qos_wmmtspecinfo *tspec_info, 2944 uint8_t *ric_buffer, uint32_t *ric_length, 2945 uint8_t *ric_identifier) 2946 { 2947 tDot11fIERICDataDesc *ric_ie; 2948 uint32_t status; 2949 2950 if (!ric_buffer || !ric_identifier || ric_length == 2951 NULL) { 2952 sme_err("RIC data is NULL, %pK, %pK, %pK", 2953 ric_buffer, ric_identifier, ric_length); 2954 return QDF_STATUS_E_FAILURE; 2955 } 2956 2957 ric_ie = qdf_mem_malloc(sizeof(*ric_ie)); 2958 if (!ric_ie) { 2959 sme_err("malloc failed for ric IE"); 2960 return QDF_STATUS_E_NOMEM; 2961 } 2962 2963 ric_ie->present = 1; 2964 ric_ie->RICData.present = 1; 2965 ric_ie->RICData.resourceDescCount = 1; 2966 ric_ie->RICData.statusCode = 0; 2967 ric_ie->RICData.Identifier = sme_qos_assign_dialog_token(); 2968 #ifndef USE_80211_WMMTSPEC_FOR_RIC 2969 ric_ie->TSPEC.present = 1; 2970 ric_ie->TSPEC.delay_bound = tspec_info->delay_bound; 2971 ric_ie->TSPEC.inactivity_int = tspec_info->inactivity_interval; 2972 ric_ie->TSPEC.burst_size = tspec_info->max_burst_size; 2973 ric_ie->TSPEC.max_msdu_size = tspec_info->maximum_msdu_size; 2974 ric_ie->TSPEC.max_service_int = tspec_info->max_service_interval; 2975 ric_ie->TSPEC.mean_data_rate = tspec_info->mean_data_rate; 2976 ric_ie->TSPEC.medium_time = 0; 2977 ric_ie->TSPEC.min_data_rate = tspec_info->min_data_rate; 2978 ric_ie->TSPEC.min_phy_rate = tspec_info->min_phy_rate; 2979 ric_ie->TSPEC.min_service_int = tspec_info->min_service_interval; 2980 ric_ie->TSPEC.size = tspec_info->nominal_msdu_size; 2981 ric_ie->TSPEC.peak_data_rate = tspec_info->peak_data_rate; 2982 ric_ie->TSPEC.surplus_bw_allowance = tspec_info->surplus_bw_allowance; 2983 ric_ie->TSPEC.suspension_int = tspec_info->suspension_interval; 2984 ric_ie->TSPEC.service_start_time = tspec_info->svc_start_time; 2985 ric_ie->TSPEC.direction = tspec_info->ts_info.direction; 2986 /* Make sure UAPSD is allowed */ 2987 if (tspec_info->ts_info.psb) 2988 ric_ie->TSPEC.psb = tspec_info->ts_info.psb; 2989 else 2990 ric_ie->TSPEC.psb = 0; 2991 2992 ric_ie->TSPEC.tsid = tspec_info->ts_info.tid; 2993 ric_ie->TSPEC.user_priority = tspec_info->ts_info.up; 2994 ric_ie->TSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; 2995 2996 *ric_identifier = ric_ie->RICData.Identifier; 2997 2998 status = dot11f_pack_ie_ric_data_desc(mac, ric_ie, ric_buffer, 2999 sizeof(*ric_ie), ric_length); 3000 if (DOT11F_FAILED(status)) { 3001 sme_err("Packing of RIC Data of length %d failed with status %d", 3002 *ric_length, status); 3003 } 3004 #else /* WMM TSPEC */ 3005 /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum 3006 * Service Interval, Service Start Time, Suspension Interval and Delay 3007 * Bound are all intended for HCCA operation and therefore must be set 3008 * to zero 3009 */ 3010 ric_ie->WMMTSPEC.present = 1; 3011 ric_ie->WMMTSPEC.version = 1; 3012 ric_ie->WMMTSPEC.delay_bound = tspec_info->delay_bound; 3013 ric_ie->WMMTSPEC.inactivity_int = tspec_info->inactivity_interval; 3014 ric_ie->WMMTSPEC.burst_size = tspec_info->max_burst_size; 3015 ric_ie->WMMTSPEC.max_msdu_size = tspec_info->maximum_msdu_size; 3016 ric_ie->WMMTSPEC.max_service_int = tspec_info->max_service_interval; 3017 ric_ie->WMMTSPEC.mean_data_rate = tspec_info->mean_data_rate; 3018 ric_ie->WMMTSPEC.medium_time = 0; 3019 ric_ie->WMMTSPEC.min_data_rate = tspec_info->min_data_rate; 3020 ric_ie->WMMTSPEC.min_phy_rate = tspec_info->min_phy_rate; 3021 ric_ie->WMMTSPEC.min_service_int = tspec_info->min_service_interval; 3022 ric_ie->WMMTSPEC.size = tspec_info->nominal_msdu_size; 3023 ric_ie->WMMTSPEC.peak_data_rate = tspec_info->peak_data_rate; 3024 ric_ie->WMMTSPEC.surplus_bw_allowance = 3025 tspec_info->surplus_bw_allowance; 3026 ric_ie->WMMTSPEC.suspension_int = tspec_info->suspension_interval; 3027 ric_ie->WMMTSPEC.service_start_time = tspec_info->svc_start_time; 3028 ric_ie->WMMTSPEC.direction = tspec_info->ts_info.direction; 3029 /* Make sure UAPSD is allowed */ 3030 if (tspec_info->ts_info.psb) 3031 ric_ie->WMMTSPEC.psb = tspec_info->ts_info.psb; 3032 else 3033 ric_ie->WMMTSPEC.psb = 0; 3034 3035 ric_ie->WMMTSPEC.tsid = tspec_info->ts_info.tid; 3036 ric_ie->WMMTSPEC.user_priority = tspec_info->ts_info.up; 3037 ric_ie->WMMTSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; 3038 3039 status = dot11f_pack_ie_ric_data_desc(mac, ric_ie, ric_buffer, 3040 sizeof(*ric_ie), ric_length); 3041 if (DOT11F_FAILED(status)) { 3042 sme_err("Packing of RIC Data of length %d failed with status %d", 3043 *ric_length, status); 3044 } 3045 #endif /* 80211_TSPEC */ 3046 *ric_identifier = ric_ie->RICData.Identifier; 3047 3048 qdf_mem_free(ric_ie); 3049 return status; 3050 } 3051 #endif 3052 3053 /** 3054 * sme_qos_process_ft_reassoc_req_ev()- processes reassoc request 3055 * 3056 * @session_id: SME Session Id 3057 * 3058 * This function Process reassoc request related to QOS 3059 * 3060 * Return: QDF_STATUS enumeration value. 3061 */ 3062 static QDF_STATUS sme_qos_process_ft_reassoc_req_ev( 3063 uint8_t sessionId) 3064 { 3065 struct sme_qos_sessioninfo *session; 3066 struct sme_qos_acinfo *ac_info; 3067 uint8_t ac, qos_requested = false; 3068 uint8_t tspec_index; 3069 struct sme_qos_flowinfoentry *flow_info = NULL; 3070 tListElem *entry = NULL; 3071 3072 sme_debug("Invoked on session %d", sessionId); 3073 3074 session = &sme_qos_cb.sessionInfo[sessionId]; 3075 3076 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 3077 ac_info = &session->ac_info[ac]; 3078 qos_requested = false; 3079 3080 for (tspec_index = 0; 3081 tspec_index < SME_QOS_TSPEC_INDEX_MAX; 3082 tspec_index++) { 3083 /* 3084 * Only in the below case, copy the AC's curr 3085 * QoS Info to requested QoS info 3086 */ 3087 if ((ac_info->ricIdentifier[tspec_index] 3088 && !ac_info->tspec_pending) 3089 || (ac_info-> 3090 tspec_mask_status & (1 << tspec_index))) { 3091 sme_debug("Copying the currentQos to requestedQos for AC=%d, flow=%d", 3092 ac, tspec_index); 3093 3094 ac_info->requested_QoSInfo[tspec_index] = 3095 ac_info->curr_QoSInfo[tspec_index]; 3096 qdf_mem_zero( 3097 &ac_info->curr_QoSInfo[tspec_index], 3098 sizeof(struct sme_qos_wmmtspecinfo)); 3099 qos_requested = true; 3100 } 3101 } 3102 3103 /* 3104 * Only if the tspec is required, transition the state to 3105 * SME_QOS_REQUESTED for this AC 3106 */ 3107 if (qos_requested) { 3108 switch (ac_info->curr_state) { 3109 case SME_QOS_HANDOFF: 3110 sme_qos_state_transition(sessionId, ac, 3111 SME_QOS_REQUESTED); 3112 break; 3113 default: 3114 sme_err("FT Reassoc req event in unexpected state %d", 3115 ac_info->curr_state); 3116 } 3117 } 3118 } 3119 3120 /* 3121 * At this point of time, we are 3122 * disconnected from the old AP, so it is safe 3123 * to reset all these session variables 3124 */ 3125 session->apsdMask = 0; 3126 3127 /* 3128 * Now change reason and HO renewal of 3129 * all the flow in this session only 3130 */ 3131 entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 3132 if (!entry) { 3133 sme_debug("Flow List empty, nothing to update"); 3134 return QDF_STATUS_E_FAILURE; 3135 } 3136 3137 do { 3138 flow_info = GET_BASE_ADDR(entry, struct sme_qos_flowinfoentry, 3139 link); 3140 if (sessionId == flow_info->sessionId) { 3141 sme_debug("Changing FlowID %d reason to SETUP and HO renewal to false", 3142 flow_info->QosFlowID); 3143 flow_info->reason = SME_QOS_REASON_SETUP; 3144 flow_info->hoRenewal = true; 3145 } 3146 entry = csr_ll_next(&sme_qos_cb.flow_list, entry, false); 3147 } while (entry); 3148 3149 return QDF_STATUS_SUCCESS; 3150 } 3151 3152 /** 3153 * sme_qos_fill_aggr_info - fill QOS Aggregation info 3154 * 3155 * @ac_id - index to the AC 3156 * @ts_id - index to TS for a given AC 3157 * @direction - traffic direction 3158 * @msg - QOS message 3159 * @session - sme session information 3160 * 3161 * this is a helper function to populate aggregation information 3162 * for QOS message. 3163 * 3164 * Return: None 3165 */ 3166 static void sme_qos_fill_aggr_info(int ac_id, int ts_id, 3167 enum sme_qos_wmm_dir_type direction, 3168 tSirAggrQosReq *msg, 3169 struct sme_qos_sessioninfo *session) 3170 { 3171 sme_debug("Found tspec entry AC=%d, flow=%d, direction = %d", 3172 ac_id, ts_id, direction); 3173 3174 msg->aggrInfo.aggrAddTsInfo[ac_id].dialogToken = 3175 sme_qos_assign_dialog_token(); 3176 msg->aggrInfo.aggrAddTsInfo[ac_id].lleTspecPresent = 3177 session->ac_info[ac_id].addTsRsp[ts_id].rsp.lleTspecPresent; 3178 msg->aggrInfo.aggrAddTsInfo[ac_id].numTclas = 3179 session->ac_info[ac_id].addTsRsp[ts_id].rsp.numTclas; 3180 qdf_mem_copy(msg->aggrInfo.aggrAddTsInfo[ac_id].tclasInfo, 3181 session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasInfo, 3182 SIR_MAC_TCLASIE_MAXNUM); 3183 msg->aggrInfo.aggrAddTsInfo[ac_id].tclasProc = 3184 session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasProc; 3185 msg->aggrInfo.aggrAddTsInfo[ac_id].tclasProcPresent = 3186 session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasProcPresent; 3187 msg->aggrInfo.aggrAddTsInfo[ac_id].tspec = 3188 session->ac_info[ac_id].addTsRsp[ts_id].rsp.tspec; 3189 msg->aggrInfo.aggrAddTsInfo[ac_id].wmeTspecPresent = 3190 session->ac_info[ac_id].addTsRsp[ts_id].rsp.wmeTspecPresent; 3191 msg->aggrInfo.aggrAddTsInfo[ac_id].wsmTspecPresent = 3192 session->ac_info[ac_id].addTsRsp[ts_id].rsp.wsmTspecPresent; 3193 msg->aggrInfo.tspecIdx |= (1 << ac_id); 3194 3195 /* Mark the index for this AC as pending for response, which would be */ 3196 /* used to validate the AddTS response from HAL->PE->SME */ 3197 session->ac_info[ac_id].tspec_pending = (1 << ts_id); 3198 3199 } 3200 3201 /** 3202 * sme_qos_ft_aggr_qos_req - send aggregated QOS request 3203 * 3204 * @mac_ctx - global MAC context 3205 * @session_id - sme session Id 3206 * 3207 * This function is used to send aggregated QOS request to HAL. 3208 * 3209 * Return: QDF_STATUS 3210 */ 3211 static QDF_STATUS sme_qos_ft_aggr_qos_req(struct mac_context *mac_ctx, uint8_t 3212 session_id) 3213 { 3214 tSirAggrQosReq *aggr_req = NULL; 3215 struct sme_qos_sessioninfo *session; 3216 QDF_STATUS status = QDF_STATUS_E_FAILURE; 3217 int i, j = 0; 3218 uint8_t direction; 3219 3220 sme_debug("invoked on session %d", session_id); 3221 3222 session = &sme_qos_cb.sessionInfo[session_id]; 3223 3224 aggr_req = qdf_mem_malloc(sizeof(tSirAggrQosReq)); 3225 if (!aggr_req) 3226 return QDF_STATUS_E_NOMEM; 3227 3228 aggr_req->messageType = eWNI_SME_FT_AGGR_QOS_REQ; 3229 aggr_req->length = sizeof(tSirAggrQosReq); 3230 aggr_req->sessionId = session_id; 3231 aggr_req->timeout = 0; 3232 aggr_req->rspReqd = true; 3233 qdf_mem_copy(&aggr_req->bssid.bytes[0], 3234 &session->assocInfo.bss_desc->bssId[0], 3235 sizeof(struct qdf_mac_addr)); 3236 3237 for (i = 0; i < QCA_WLAN_AC_ALL; i++) { 3238 for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { 3239 sme_debug("ac=%d, tspec_mask_status=%x, tspec_index=%d direction = %d", 3240 i, session->ac_info[i].tspec_mask_status, j, 3241 session->ac_info[i].addTsRsp[j].rsp.tspec. 3242 tsinfo.traffic.direction); 3243 /* Check if any flow is active on this AC */ 3244 if (!((session->ac_info[i].tspec_mask_status) & 3245 (1 << j))) 3246 continue; 3247 3248 direction = session->ac_info[i].addTsRsp[j].rsp.tspec. 3249 tsinfo.traffic.direction; 3250 3251 if ((direction == SME_QOS_WMM_TS_DIR_UPLINK) || 3252 (direction == SME_QOS_WMM_TS_DIR_BOTH)) 3253 sme_qos_fill_aggr_info(i, j, direction, 3254 aggr_req, session); 3255 } 3256 } 3257 3258 sme_debug("Sending aggregated message to HAL 0x%x", 3259 aggr_req->aggrInfo.tspecIdx); 3260 3261 if (QDF_IS_STATUS_SUCCESS(umac_send_mb_message_to_mac(aggr_req))) { 3262 status = QDF_STATUS_SUCCESS; 3263 sme_info("sent down a AGGR QoS req to PE"); 3264 } 3265 3266 return status; 3267 } 3268 3269 static 3270 QDF_STATUS sme_qos_process_ftric_response(struct mac_context *mac, 3271 uint8_t sessionId, 3272 tDot11fIERICDataDesc *pRicDataDesc, 3273 uint8_t ac, uint8_t tspecIndex) 3274 { 3275 uint8_t i = 0; 3276 tpSirAddtsRsp pAddtsRsp = &sme_qos_cb.sessionInfo[sessionId]. 3277 ac_info[ac].addTsRsp[tspecIndex]; 3278 3279 qdf_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp)); 3280 3281 pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP; 3282 pAddtsRsp->length = sizeof(tSirAddtsRsp); 3283 pAddtsRsp->rc = pRicDataDesc->RICData.statusCode; 3284 pAddtsRsp->sessionId = sessionId; 3285 pAddtsRsp->rsp.dialogToken = pRicDataDesc->RICData.Identifier; 3286 pAddtsRsp->rsp.status = pRicDataDesc->RICData.statusCode; 3287 pAddtsRsp->rsp.wmeTspecPresent = pRicDataDesc->TSPEC.present; 3288 if (pAddtsRsp->rsp.wmeTspecPresent) 3289 /* Copy TSPEC params received in RIC response to addts 3290 * response 3291 */ 3292 convert_tspec(mac, &pAddtsRsp->rsp.tspec, 3293 &pRicDataDesc->TSPEC); 3294 3295 pAddtsRsp->rsp.numTclas = pRicDataDesc->num_TCLAS; 3296 if (pAddtsRsp->rsp.numTclas) { 3297 for (i = 0; i < pAddtsRsp->rsp.numTclas; i++) 3298 /* Copy TCLAS info per index to the addts response */ 3299 convert_tclas(mac, &pAddtsRsp->rsp.tclasInfo[i], 3300 &pRicDataDesc->TCLAS[i]); 3301 } 3302 3303 pAddtsRsp->rsp.tclasProcPresent = pRicDataDesc->TCLASSPROC.present; 3304 if (pAddtsRsp->rsp.tclasProcPresent) 3305 pAddtsRsp->rsp.tclasProc = pRicDataDesc->TCLASSPROC.processing; 3306 3307 pAddtsRsp->rsp.schedulePresent = pRicDataDesc->Schedule.present; 3308 if (pAddtsRsp->rsp.schedulePresent) { 3309 /* Copy Schedule IE params to addts response */ 3310 convert_schedule(mac, &pAddtsRsp->rsp.schedule, 3311 &pRicDataDesc->Schedule); 3312 } 3313 /* Need to check the below portion is a part of WMM TSPEC */ 3314 /* Process Delay element */ 3315 if (pRicDataDesc->TSDelay.present) 3316 convert_ts_delay(mac, &pAddtsRsp->rsp.delay, 3317 &pRicDataDesc->TSDelay); 3318 3319 /* Need to call for WMMTSPEC */ 3320 if (pRicDataDesc->WMMTSPEC.present) 3321 convert_wmmtspec(mac, &pAddtsRsp->rsp.tspec, 3322 &pRicDataDesc->WMMTSPEC); 3323 3324 /* return sme_qos_process_add_ts_rsp(mac, &addtsRsp); */ 3325 return QDF_STATUS_SUCCESS; 3326 } 3327 3328 /** 3329 * sme_qos_process_aggr_qos_rsp - process qos aggregation response 3330 * 3331 * @mac_ctx - global mac context 3332 * @msgbuf - SME message buffer 3333 * 3334 * this function process the QOS aggregation response received. 3335 * 3336 * Return: QDF_STATUS 3337 */ 3338 static QDF_STATUS sme_qos_process_aggr_qos_rsp(struct mac_context *mac_ctx, 3339 void *msgbuf) 3340 { 3341 tpSirAggrQosRsp rsp = (tpSirAggrQosRsp) msgbuf; 3342 tSirAddtsRsp addtsrsp; 3343 QDF_STATUS status = QDF_STATUS_SUCCESS; 3344 int i, j = 0; 3345 uint8_t sessionid = rsp->sessionId; 3346 3347 sme_debug("Received AGGR_QOS resp from LIM"); 3348 3349 /* Copy the updated response information for TSPEC of all the ACs */ 3350 for (i = 0; i < QCA_WLAN_AC_ALL; i++) { 3351 uint8_t tspec_mask_status = 3352 sme_qos_cb.sessionInfo[sessionid].ac_info[i]. 3353 tspec_mask_status; 3354 for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { 3355 uint8_t direction = 3356 sme_qos_cb.sessionInfo[sessionid]. 3357 ac_info[i].addTsRsp[j].rsp.tspec.tsinfo.traffic. 3358 direction; 3359 3360 sme_debug("Addts rsp from LIM AC=%d, flow=%d dir=%d, tspecIdx=%x", 3361 i, j, direction, rsp->aggrInfo.tspecIdx); 3362 3363 /* Check if the direction is Uplink or bi-directional */ 3364 if (!(((1 << i) & rsp->aggrInfo.tspecIdx) && 3365 ((tspec_mask_status) & (1 << j)) && 3366 ((direction == SME_QOS_WMM_TS_DIR_UPLINK) || 3367 (direction == SME_QOS_WMM_TS_DIR_BOTH)))) { 3368 continue; 3369 } 3370 addtsrsp = 3371 sme_qos_cb.sessionInfo[sessionid].ac_info[i]. 3372 addTsRsp[j]; 3373 addtsrsp.rc = rsp->aggrInfo.aggrRsp[i].status; 3374 addtsrsp.rsp.status = rsp->aggrInfo.aggrRsp[i].status; 3375 addtsrsp.rsp.tspec = rsp->aggrInfo.aggrRsp[i].tspec; 3376 3377 sme_debug("Processing Addts rsp from LIM AC=%d, flow=%d", 3378 i, j); 3379 /* post ADD TS response for each */ 3380 if (sme_qos_process_add_ts_rsp(mac_ctx, &addtsrsp) != 3381 QDF_STATUS_SUCCESS) 3382 status = QDF_STATUS_E_FAILURE; 3383 } 3384 } 3385 return status; 3386 } 3387 3388 /** 3389 * sme_qos_find_matching_tspec() - utility function to find matching tspec 3390 * @mac_ctx: global MAC context 3391 * @sessionid: session ID 3392 * @ac: AC index 3393 * @ac_info: Current AC info 3394 * @ric_data_desc: pointer to ric data 3395 * @ric_rsplen: pointer to ric response length 3396 * 3397 * This utility function is called by sme_qos_process_ft_reassoc_rsp_ev 3398 * to find the matching tspec 3399 * 3400 * Return: QDF_STATUS 3401 */ 3402 static QDF_STATUS sme_qos_find_matching_tspec(struct mac_context *mac_ctx, 3403 uint8_t sessionid, uint8_t ac, struct sme_qos_acinfo *ac_info, 3404 tDot11fIERICDataDesc *ric_data_desc, uint32_t *ric_rsplen) 3405 { 3406 uint8_t tspec_flow_index; 3407 QDF_STATUS status = QDF_STATUS_SUCCESS; 3408 3409 sme_debug("invoked on session %d", sessionid); 3410 3411 for (tspec_flow_index = 0; 3412 tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; tspec_flow_index++) { 3413 /* 3414 * Only in the below case, copy the AC's curr QoS Info 3415 * to requested QoS info 3416 */ 3417 if (!ac_info->ricIdentifier[tspec_flow_index]) 3418 continue; 3419 3420 if (!*ric_rsplen) { 3421 sme_err("RIC Response not received for AC %d on TSPEC Index %d, RIC Req Identifier = %d", 3422 ac, tspec_flow_index, 3423 ac_info->ricIdentifier[tspec_flow_index]); 3424 continue; 3425 } 3426 /* Now we got response for this identifier. Process it. */ 3427 if (!ric_data_desc->present) 3428 continue; 3429 if (!ric_data_desc->RICData.present) 3430 continue; 3431 3432 if (ric_data_desc->RICData.Identifier != 3433 ac_info->ricIdentifier[tspec_flow_index]) { 3434 sme_err("RIC response order not same as request sent. Request ID = %d, Response ID = %d", 3435 ac_info->ricIdentifier[tspec_flow_index], 3436 ric_data_desc->RICData.Identifier); 3437 } else { 3438 sme_debug("Processing RIC Response for AC %d, TSPEC Flow index %d with RIC ID %d", 3439 ac, tspec_flow_index, 3440 ric_data_desc->RICData.Identifier); 3441 status = sme_qos_process_ftric_response(mac_ctx, 3442 sessionid, ric_data_desc, ac, 3443 tspec_flow_index); 3444 if (QDF_STATUS_SUCCESS != status) { 3445 sme_err("Failed with status %d for AC %d in TSPEC Flow index = %d", 3446 status, ac, tspec_flow_index); 3447 } 3448 } 3449 ric_data_desc++; 3450 *ric_rsplen -= sizeof(tDot11fIERICDataDesc); 3451 } 3452 return status; 3453 } 3454 3455 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 3456 /** 3457 * sme_qos_find_matching_tspec_lfr3() - utility function to find matching tspec 3458 * @mac_ctx: global MAC context 3459 * @sessionid: session ID 3460 * @ac: AC index 3461 * @qos_session: QOS session 3462 * @ric_data_desc: pointer to ric data 3463 * @ric_rsplen: ric response length 3464 * 3465 * This utility function is called by sme_qos_process_ft_reassoc_rsp_ev 3466 * to find the matching tspec while LFR3 is enabled. 3467 * 3468 * Return: QDF_STATUS 3469 */ 3470 static QDF_STATUS sme_qos_find_matching_tspec_lfr3(struct mac_context *mac_ctx, 3471 uint8_t sessionid, uint8_t ac, struct sme_qos_sessioninfo 3472 *qos_session, 3473 tDot11fIERICDataDesc *ric_data_desc, uint32_t ric_rsplen) 3474 { 3475 struct sme_qos_acinfo *ac_info; 3476 uint8_t tspec_flow_idx; 3477 bool found = false; 3478 enum sme_qos_wmm_dir_type direction, qos_dir; 3479 uint8_t ac1; 3480 tDot11fIERICDataDesc *ric_data = NULL; 3481 uint32_t ric_len; 3482 QDF_STATUS status = QDF_STATUS_SUCCESS; 3483 3484 sme_debug("invoked on session %d", sessionid); 3485 3486 if (ac == QCA_WLAN_AC_ALL) { 3487 sme_err("Invalid AC %d", ac); 3488 return QDF_STATUS_E_FAILURE; 3489 } 3490 ric_data = ric_data_desc; 3491 ric_len = ric_rsplen; 3492 ac_info = &qos_session->ac_info[ac]; 3493 for (tspec_flow_idx = 0; tspec_flow_idx < SME_QOS_TSPEC_INDEX_MAX; 3494 tspec_flow_idx++) { 3495 if (!((qos_session->ac_info[ac].tspec_mask_status) & 3496 (1 << tspec_flow_idx))) 3497 goto sme_qos_next_ric; 3498 qos_dir = 3499 ac_info->requested_QoSInfo[tspec_flow_idx].ts_info.direction; 3500 do { 3501 ac1 = sme_qos_up_to_ac( 3502 ric_data->WMMTSPEC.user_priority); 3503 if (ac1 == QCA_WLAN_AC_ALL) { 3504 sme_err("Invalid AC %d UP %d", ac1, 3505 ric_data->WMMTSPEC.user_priority); 3506 break; 3507 } 3508 direction = ric_data->WMMTSPEC.direction; 3509 if (ac == ac1 && direction == qos_dir) { 3510 found = true; 3511 status = sme_qos_process_ftric_response(mac_ctx, 3512 sessionid, ric_data, ac, 3513 tspec_flow_idx); 3514 if (QDF_STATUS_SUCCESS != status) { 3515 sme_err("Failed with status %d for AC %d in TSPEC Flow index = %d", 3516 status, ac, tspec_flow_idx); 3517 } 3518 break; 3519 } 3520 ric_data++; 3521 ric_len -= sizeof(tDot11fIERICDataDesc); 3522 } while (ric_len); 3523 sme_qos_next_ric: 3524 ric_data = ric_data_desc; 3525 ric_len = ric_rsplen; 3526 found = false; 3527 } 3528 3529 return status; 3530 } 3531 #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ 3532 3533 static 3534 QDF_STATUS sme_qos_process_ft_reassoc_rsp_ev(struct mac_context *mac_ctx, 3535 uint8_t sessionid, void *event_info) 3536 { 3537 struct sme_qos_sessioninfo *qos_session; 3538 struct sme_qos_acinfo *ac_info; 3539 uint8_t ac; 3540 tDot11fIERICDataDesc *ric_data_desc = NULL; 3541 QDF_STATUS status = QDF_STATUS_SUCCESS; 3542 struct csr_roam_session *csr_session = CSR_GET_SESSION(mac_ctx, 3543 sessionid); 3544 struct csr_roam_connectedinfo *csr_conn_info = NULL; 3545 uint32_t ric_rsplen; 3546 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 3547 tDot11fIERICDataDesc *ric_data = NULL; 3548 uint32_t ric_len; 3549 #endif 3550 3551 if (!csr_session) { 3552 sme_err("The Session pointer is NULL"); 3553 return QDF_STATUS_E_FAILURE; 3554 } 3555 csr_conn_info = &csr_session->connectedInfo; 3556 ric_rsplen = csr_conn_info->nRICRspLength; 3557 3558 sme_debug("invoked on session %d", sessionid); 3559 3560 qos_session = &sme_qos_cb.sessionInfo[sessionid]; 3561 3562 ric_data_desc = (tDot11fIERICDataDesc *) ((csr_conn_info->pbFrames) + 3563 (csr_conn_info->nBeaconLength + 3564 csr_conn_info->nAssocReqLength + 3565 csr_conn_info->nAssocRspLength)); 3566 3567 if (!wlan_cm_is_roam_sync_in_progress(mac_ctx->psoc, sessionid)) { 3568 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 3569 ac_info = &qos_session->ac_info[ac]; 3570 sme_qos_find_matching_tspec(mac_ctx, sessionid, ac, 3571 ac_info, ric_data_desc, &ric_rsplen); 3572 } 3573 3574 if (ric_rsplen) { 3575 sme_err("RIC Resp still follows . Rem len = %d", 3576 ric_rsplen); 3577 } 3578 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 3579 } else { 3580 sme_debug("LFR3-11r Compare RIC in Reassoc Resp to find matching tspec in host"); 3581 ric_data = ric_data_desc; 3582 ric_len = ric_rsplen; 3583 if (ric_rsplen && ric_data_desc->present && 3584 ric_data_desc->WMMTSPEC.present) { 3585 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; 3586 ac++) { 3587 sme_qos_find_matching_tspec_lfr3(mac_ctx, 3588 sessionid, ac, qos_session, ric_data, 3589 ric_len); 3590 } 3591 } else 3592 sme_debug("LFR3-11r ric_rsplen is zero or ric_data_desc is not present or wmmtspec is not present"); 3593 #endif 3594 } 3595 3596 /* Send the Aggregated QoS request to HAL */ 3597 status = sme_qos_ft_aggr_qos_req(mac_ctx, sessionid); 3598 3599 return status; 3600 } 3601 3602 #ifdef WLAN_FEATURE_MSCS 3603 void sme_send_mscs_action_frame(uint8_t vdev_id) 3604 { 3605 struct mscs_req_info *mscs_req; 3606 struct sme_qos_sessioninfo *qos_session; 3607 struct scheduler_msg msg = {0}; 3608 QDF_STATUS qdf_status; 3609 3610 qos_session = &sme_qos_cb.sessionInfo[vdev_id]; 3611 if (!qos_session) { 3612 sme_debug("qos_session is NULL"); 3613 return; 3614 } 3615 mscs_req = qdf_mem_malloc(sizeof(*mscs_req)); 3616 if (!mscs_req) 3617 return; 3618 3619 mscs_req->vdev_id = vdev_id; 3620 if (!qos_session->assocInfo.bss_desc) { 3621 sme_err("BSS descriptor is NULL so we won't send request to PE"); 3622 qdf_mem_free(mscs_req); 3623 return; 3624 } 3625 qdf_mem_copy(&mscs_req->bssid.bytes[0], 3626 &qos_session->assocInfo.bss_desc->bssId[0], 3627 sizeof(struct qdf_mac_addr)); 3628 3629 mscs_req->dialog_token = sme_qos_assign_dialog_token(); 3630 mscs_req->dec.request_type = SCS_REQ_ADD; 3631 mscs_req->dec.user_priority_control = MSCS_USER_PRIORITY; 3632 mscs_req->dec.stream_timeout = (MSCS_STREAM_TIMEOUT * 1000); 3633 mscs_req->dec.tclas_mask.classifier_type = MSCS_TCLAS_CLASSIFIER_TYPE; 3634 mscs_req->dec.tclas_mask.classifier_mask = MSCS_TCLAS_CLASSIFIER_MASK; 3635 3636 msg.type = eWNI_SME_MSCS_REQ; 3637 msg.reserved = 0; 3638 msg.bodyptr = mscs_req; 3639 qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_PE, 3640 QDF_MODULE_ID_PE, &msg); 3641 if (QDF_IS_STATUS_ERROR(qdf_status)) { 3642 sme_err("Fail to send mscs request to PE"); 3643 qdf_mem_free(mscs_req); 3644 } 3645 } 3646 #endif 3647 3648 /** 3649 * sme_qos_add_ts_req() - send ADDTS request. 3650 * @mac: Pointer to the global MAC parameter structure. 3651 * @sessionId: Session upon which the TSPEC should be added 3652 * @pTspec_Info: Pointer to struct sme_qos_wmmtspecinfo which contains the WMM 3653 * TSPEC related info as defined above 3654 * @ac: Enumeration of the various EDCA Access Categories. 3655 * 3656 * This function is used to send down the ADDTS request with TSPEC params to PE 3657 * 3658 * Return: QDF_STATUS 3659 */ 3660 static QDF_STATUS sme_qos_add_ts_req(struct mac_context *mac, 3661 uint8_t sessionId, 3662 struct sme_qos_wmmtspecinfo *pTspec_Info, 3663 enum qca_wlan_ac_type ac) 3664 { 3665 tSirAddtsReq *pMsg = NULL; 3666 struct sme_qos_sessioninfo *pSession; 3667 QDF_STATUS status = QDF_STATUS_E_FAILURE; 3668 #ifdef FEATURE_WLAN_DIAG_SUPPORT 3669 WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); 3670 #endif 3671 sme_debug("invoked on session %d for AC %d", sessionId, ac); 3672 if (sessionId >= WLAN_MAX_VDEVS) { 3673 /* err msg */ 3674 sme_err("sessionId(%d) is invalid", sessionId); 3675 return QDF_STATUS_E_FAILURE; 3676 } 3677 3678 pSession = &sme_qos_cb.sessionInfo[sessionId]; 3679 pMsg = qdf_mem_malloc(sizeof(tSirAddtsReq)); 3680 if (!pMsg) 3681 return QDF_STATUS_E_NOMEM; 3682 3683 pMsg->messageType = eWNI_SME_ADDTS_REQ; 3684 pMsg->length = sizeof(tSirAddtsReq); 3685 pMsg->sessionId = sessionId; 3686 pMsg->timeout = 0; 3687 pMsg->rspReqd = true; 3688 pMsg->req.dialogToken = sme_qos_assign_dialog_token(); 3689 /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum 3690 * Service Interval, Service Start Time, Suspension Interval and Delay 3691 * Bound are all intended for HCCA operation and therefore must be set 3692 * to zero 3693 */ 3694 pMsg->req.tspec.delayBound = 0; 3695 pMsg->req.tspec.inactInterval = pTspec_Info->inactivity_interval; 3696 pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH; 3697 pMsg->req.tspec.maxBurstSz = pTspec_Info->max_burst_size; 3698 pMsg->req.tspec.maxMsduSz = pTspec_Info->maximum_msdu_size; 3699 pMsg->req.tspec.maxSvcInterval = pTspec_Info->max_service_interval; 3700 pMsg->req.tspec.meanDataRate = pTspec_Info->mean_data_rate; 3701 pMsg->req.tspec.mediumTime = pTspec_Info->medium_time; 3702 pMsg->req.tspec.minDataRate = pTspec_Info->min_data_rate; 3703 pMsg->req.tspec.minPhyRate = pTspec_Info->min_phy_rate; 3704 pMsg->req.tspec.minSvcInterval = pTspec_Info->min_service_interval; 3705 pMsg->req.tspec.nomMsduSz = pTspec_Info->nominal_msdu_size; 3706 pMsg->req.tspec.peakDataRate = pTspec_Info->peak_data_rate; 3707 pMsg->req.tspec.surplusBw = pTspec_Info->surplus_bw_allowance; 3708 pMsg->req.tspec.suspendInterval = pTspec_Info->suspension_interval; 3709 pMsg->req.tspec.svcStartTime = 0; 3710 pMsg->req.tspec.tsinfo.traffic.direction = 3711 pTspec_Info->ts_info.direction; 3712 /* Make sure UAPSD is allowed */ 3713 if (pTspec_Info->ts_info.psb) { 3714 pMsg->req.tspec.tsinfo.traffic.psb = pTspec_Info->ts_info.psb; 3715 } else { 3716 pMsg->req.tspec.tsinfo.traffic.psb = 0; 3717 pTspec_Info->ts_info.psb = 0; 3718 } 3719 pMsg->req.tspec.tsinfo.traffic.tsid = pTspec_Info->ts_info.tid; 3720 pMsg->req.tspec.tsinfo.traffic.userPrio = pTspec_Info->ts_info.up; 3721 pMsg->req.tspec.tsinfo.traffic.accessPolicy = 3722 SME_QOS_ACCESS_POLICY_EDCA; 3723 pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = 3724 pTspec_Info->ts_info.burst_size_defn; 3725 pMsg->req.tspec.tsinfo.traffic.ackPolicy = 3726 pTspec_Info->ts_info.ack_policy; 3727 pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE; 3728 /*Fill the BSSID pMsg->req.bssId */ 3729 if (!pSession->assocInfo.bss_desc) { 3730 sme_err("BSS descriptor is NULL so we don't send request to PE"); 3731 qdf_mem_free(pMsg); 3732 return QDF_STATUS_E_FAILURE; 3733 } 3734 qdf_mem_copy(&pMsg->bssid.bytes[0], 3735 &pSession->assocInfo.bss_desc->bssId[0], 3736 sizeof(struct qdf_mac_addr)); 3737 sme_debug("up = %d, tid = %d", 3738 pTspec_Info->ts_info.up, pTspec_Info->ts_info.tid); 3739 #ifdef FEATURE_WLAN_ESE 3740 if (wlan_cm_get_ese_assoc(mac->pdev, sessionId)) { 3741 pMsg->req.tsrsIE.tsid = pTspec_Info->ts_info.up; 3742 pMsg->req.tsrsPresent = 1; 3743 } 3744 #endif 3745 if (QDF_IS_STATUS_SUCCESS(umac_send_mb_message_to_mac(pMsg))) { 3746 status = QDF_STATUS_SUCCESS; 3747 sme_debug("sent down a ADDTS req to PE"); 3748 /* event: EVENT_WLAN_QOS */ 3749 #ifdef FEATURE_WLAN_DIAG_SUPPORT 3750 qos.eventId = SME_QOS_DIAG_ADDTS_REQ; 3751 qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED; 3752 WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); 3753 #endif /* FEATURE_WLAN_DIAG_SUPPORT */ 3754 } 3755 return status; 3756 } 3757 3758 /* 3759 * sme_qos_del_ts_req() - To send down the DELTS request with TSPEC params 3760 * to PE 3761 * 3762 * mac - Pointer to the global MAC parameter structure. 3763 * sessionId - Session from which the TSPEC should be deleted 3764 * ac - Enumeration of the various EDCA Access Categories. 3765 * tspec_mask - on which tspec per AC, the delts is requested 3766 * Return QDF_STATUS 3767 */ 3768 static QDF_STATUS sme_qos_del_ts_req(struct mac_context *mac, 3769 uint8_t sessionId, 3770 enum qca_wlan_ac_type ac, uint8_t tspec_mask) 3771 { 3772 struct sme_qos_sessioninfo *pSession; 3773 struct sme_qos_acinfo *pACInfo; 3774 tSirDeltsReq *pMsg; 3775 struct sme_qos_wmmtspecinfo *pTspecInfo; 3776 struct mac_ts_info tsinfo; 3777 3778 #ifdef FEATURE_WLAN_DIAG_SUPPORT 3779 WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); 3780 #endif 3781 sme_debug("invoked on session %d for AC %d", sessionId, ac); 3782 pMsg = qdf_mem_malloc(sizeof(tSirDeltsReq)); 3783 if (!pMsg) 3784 return QDF_STATUS_E_NOMEM; 3785 3786 /* get pointer to the TSPEC being deleted */ 3787 pSession = &sme_qos_cb.sessionInfo[sessionId]; 3788 pACInfo = &pSession->ac_info[ac]; 3789 pTspecInfo = &pACInfo->curr_QoSInfo[tspec_mask - 1]; 3790 pMsg->messageType = eWNI_SME_DELTS_REQ; 3791 pMsg->length = sizeof(tSirDeltsReq); 3792 pMsg->sessionId = sessionId; 3793 pMsg->rspReqd = true; 3794 pMsg->req.tspec.delayBound = pTspecInfo->delay_bound; 3795 pMsg->req.tspec.inactInterval = pTspecInfo->inactivity_interval; 3796 pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH; 3797 pMsg->req.tspec.maxBurstSz = pTspecInfo->max_burst_size; 3798 pMsg->req.tspec.maxMsduSz = pTspecInfo->maximum_msdu_size; 3799 pMsg->req.tspec.maxSvcInterval = pTspecInfo->max_service_interval; 3800 pMsg->req.tspec.meanDataRate = pTspecInfo->mean_data_rate; 3801 pMsg->req.tspec.mediumTime = pTspecInfo->medium_time; 3802 pMsg->req.tspec.minDataRate = pTspecInfo->min_data_rate; 3803 pMsg->req.tspec.minPhyRate = pTspecInfo->min_phy_rate; 3804 pMsg->req.tspec.minSvcInterval = pTspecInfo->min_service_interval; 3805 pMsg->req.tspec.nomMsduSz = pTspecInfo->nominal_msdu_size; 3806 pMsg->req.tspec.peakDataRate = pTspecInfo->peak_data_rate; 3807 pMsg->req.tspec.surplusBw = pTspecInfo->surplus_bw_allowance; 3808 pMsg->req.tspec.suspendInterval = pTspecInfo->suspension_interval; 3809 pMsg->req.tspec.svcStartTime = pTspecInfo->svc_start_time; 3810 pMsg->req.tspec.tsinfo.traffic.direction = 3811 pTspecInfo->ts_info.direction; 3812 pMsg->req.tspec.tsinfo.traffic.psb = pTspecInfo->ts_info.psb; 3813 pMsg->req.tspec.tsinfo.traffic.tsid = pTspecInfo->ts_info.tid; 3814 pMsg->req.tspec.tsinfo.traffic.userPrio = pTspecInfo->ts_info.up; 3815 pMsg->req.tspec.tsinfo.traffic.accessPolicy = 3816 SME_QOS_ACCESS_POLICY_EDCA; 3817 pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = 3818 pTspecInfo->ts_info.burst_size_defn; 3819 pMsg->req.tspec.tsinfo.traffic.ackPolicy = 3820 pTspecInfo->ts_info.ack_policy; 3821 pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE; 3822 /*Fill the BSSID pMsg->req.bssId */ 3823 if (!pSession->assocInfo.bss_desc) { 3824 sme_err("BSS descriptor is NULL so we don't send request to PE"); 3825 qdf_mem_free(pMsg); 3826 return QDF_STATUS_E_FAILURE; 3827 } 3828 qdf_mem_copy(&pMsg->bssid.bytes[0], 3829 &pSession->assocInfo.bss_desc->bssId[0], 3830 sizeof(struct qdf_mac_addr)); 3831 3832 sme_debug("up = %d, tid = %d", 3833 pTspecInfo->ts_info.up, pTspecInfo->ts_info.tid); 3834 qdf_mem_zero(&pACInfo->curr_QoSInfo[tspec_mask - 1], 3835 sizeof(struct sme_qos_wmmtspecinfo)); 3836 qdf_mem_copy(&tsinfo, &pMsg->req.tspec.tsinfo, 3837 sizeof(struct mac_ts_info)); 3838 3839 if (!QDF_IS_STATUS_SUCCESS(umac_send_mb_message_to_mac(pMsg))) { 3840 sme_err("DELTS req to PE failed"); 3841 return QDF_STATUS_E_FAILURE; 3842 } 3843 3844 sme_debug("sent down a DELTS req to PE"); 3845 #ifdef FEATURE_WLAN_DIAG_SUPPORT 3846 qos.eventId = SME_QOS_DIAG_DELTS; 3847 qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED; 3848 WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); 3849 #endif 3850 3851 sme_set_tspec_uapsd_mask_per_session(mac, &tsinfo, sessionId); 3852 3853 return QDF_STATUS_SUCCESS; 3854 } 3855 3856 /* 3857 * sme_qos_process_add_ts_rsp() - Function to process the 3858 * eWNI_SME_ADDTS_RSP came from PE 3859 * 3860 * @mac - Pointer to the global MAC parameter structure. 3861 * @msg_buf - Pointer to the msg buffer came from PE. 3862 * Return QDF_STATUS 3863 */ 3864 static QDF_STATUS sme_qos_process_add_ts_rsp(struct mac_context *mac, 3865 void *msg_buf) 3866 { 3867 tpSirAddtsRsp paddts_rsp = (tpSirAddtsRsp) msg_buf; 3868 struct sme_qos_sessioninfo *pSession; 3869 uint8_t sessionId = paddts_rsp->sessionId; 3870 QDF_STATUS status = QDF_STATUS_E_FAILURE; 3871 enum sme_qos_wmmuptype up = 3872 (enum sme_qos_wmmuptype) 3873 paddts_rsp->rsp.tspec.tsinfo.traffic.userPrio; 3874 struct sme_qos_acinfo *pACInfo; 3875 enum qca_wlan_ac_type ac; 3876 #ifdef FEATURE_WLAN_DIAG_SUPPORT 3877 WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); 3878 #endif 3879 3880 pSession = &sme_qos_cb.sessionInfo[sessionId]; 3881 3882 sme_debug("invoked on session %d for UP %d", sessionId, up); 3883 3884 ac = sme_qos_up_to_ac(up); 3885 if (QCA_WLAN_AC_ALL == ac) { 3886 /* err msg */ 3887 sme_err("invalid AC %d from UP %d", ac, up); 3888 3889 return QDF_STATUS_E_FAILURE; 3890 } 3891 pACInfo = &pSession->ac_info[ac]; 3892 if (SME_QOS_HANDOFF == pACInfo->curr_state) { 3893 sme_debug("ADDTS Rsp received for AC %d in HANDOFF State. Dropping", 3894 ac); 3895 return QDF_STATUS_SUCCESS; 3896 } 3897 3898 sme_debug("Invoked on session %d with return code %d", 3899 sessionId, paddts_rsp->rc); 3900 if (paddts_rsp->rc) { 3901 /* event: EVENT_WLAN_QOS */ 3902 #ifdef FEATURE_WLAN_DIAG_SUPPORT 3903 qos.eventId = SME_QOS_DIAG_ADDTS_RSP; 3904 qos.reasonCode = SME_QOS_DIAG_ADDTS_REFUSED; 3905 WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); 3906 #endif /* FEATURE_WLAN_DIAG_SUPPORT */ 3907 status = 3908 sme_qos_process_add_ts_failure_rsp(mac, sessionId, 3909 &paddts_rsp->rsp); 3910 } else { 3911 status = 3912 sme_qos_process_add_ts_success_rsp(mac, sessionId, 3913 &paddts_rsp->rsp); 3914 } 3915 return status; 3916 } 3917 3918 /* 3919 * sme_qos_process_del_ts_rsp() - Function to process the 3920 * eWNI_SME_DELTS_RSP came from PE 3921 * 3922 * mac - Pointer to the global MAC parameter structure. 3923 * msg_buf - Pointer to the msg buffer came from PE. 3924 * 3925 * Return QDF_STATUS 3926 */ 3927 static 3928 QDF_STATUS sme_qos_process_del_ts_rsp(struct mac_context *mac, void *msg_buf) 3929 { 3930 tpSirDeltsRsp pDeltsRsp = (tpSirDeltsRsp) msg_buf; 3931 struct sme_qos_sessioninfo *pSession; 3932 uint8_t sessionId = pDeltsRsp->sessionId; 3933 3934 /* msg */ 3935 sme_debug("Invoked on session %d with return code %d", 3936 sessionId, pDeltsRsp->rc); 3937 pSession = &sme_qos_cb.sessionInfo[sessionId]; 3938 (void)sme_qos_process_buffered_cmd(sessionId); 3939 return QDF_STATUS_SUCCESS; 3940 } 3941 3942 /* 3943 * sme_qos_process_del_ts_ind() - Function to process the 3944 * eWNI_SME_DELTS_IND came from PE 3945 * 3946 * Since it's a DELTS indication from AP, will notify all the flows running on 3947 * this AC about QoS release 3948 * 3949 * mac - Pointer to the global MAC parameter structure. 3950 * msg_buf - Pointer to the msg buffer came from PE. 3951 * 3952 * Return QDF_STATUS 3953 */ 3954 static QDF_STATUS sme_qos_process_del_ts_ind(struct mac_context *mac, 3955 void *msg_buf) 3956 { 3957 tpSirDeltsRsp pdeltsind = (tpSirDeltsRsp)msg_buf; 3958 struct sme_qos_sessioninfo *pSession; 3959 struct sme_qos_acinfo *pACInfo; 3960 uint8_t sessionId = pdeltsind->sessionId; 3961 enum qca_wlan_ac_type ac; 3962 struct sme_qos_searchinfo search_key; 3963 struct mac_ts_info *tsinfo; 3964 enum sme_qos_wmmuptype up = 3965 (enum sme_qos_wmmuptype) 3966 pdeltsind->rsp.tspec.tsinfo.traffic.userPrio; 3967 #ifdef FEATURE_WLAN_DIAG_SUPPORT 3968 WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); 3969 #endif 3970 sme_debug("Invoked on session %d for UP %d", sessionId, up); 3971 tsinfo = &pdeltsind->rsp.tspec.tsinfo; 3972 ac = sme_qos_up_to_ac(up); 3973 if (QCA_WLAN_AC_ALL == ac) { 3974 /* err msg */ 3975 sme_err("invalid AC %d from UP %d", ac, up); 3976 return QDF_STATUS_E_FAILURE; 3977 } 3978 pSession = &sme_qos_cb.sessionInfo[sessionId]; 3979 pACInfo = &pSession->ac_info[ac]; 3980 3981 qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); 3982 /* set the key type & the key to be searched in the Flow List */ 3983 search_key.key.ac_type = ac; 3984 search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; 3985 search_key.sessionId = sessionId; 3986 /* find all Flows on the particular AC & delete them, also send HDD 3987 * indication through the callback it registered per request 3988 */ 3989 if (!QDF_IS_STATUS_SUCCESS 3990 (sme_qos_find_all_in_flow_list(mac, search_key, 3991 sme_qos_del_ts_ind_fnp))) { 3992 sme_err("no match found for ac = %d", search_key.key.ac_type); 3993 return QDF_STATUS_E_FAILURE; 3994 } 3995 sme_set_tspec_uapsd_mask_per_session(mac, tsinfo, sessionId); 3996 /* event: EVENT_WLAN_QOS */ 3997 #ifdef FEATURE_WLAN_DIAG_SUPPORT 3998 qos.eventId = SME_QOS_DIAG_DELTS; 3999 qos.reasonCode = SME_QOS_DIAG_DELTS_IND_FROM_AP; 4000 WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); 4001 #endif /* FEATURE_WLAN_DIAG_SUPPORT */ 4002 4003 return QDF_STATUS_SUCCESS; 4004 } 4005 4006 /* 4007 * sme_qos_process_assoc_complete_ev() - Function to process the 4008 * SME_QOS_CSR_ASSOC_COMPLETE event indication from CSR 4009 * 4010 * pEvent_info - Pointer to relevant info from CSR. 4011 * 4012 * Return QDF_STATUS 4013 */ 4014 static QDF_STATUS sme_qos_process_assoc_complete_ev(struct mac_context *mac, uint8_t 4015 sessionId, void *pEvent_info) 4016 { 4017 struct sme_qos_sessioninfo *pSession; 4018 struct sme_qos_acinfo *pACInfo; 4019 QDF_STATUS status = QDF_STATUS_E_FAILURE; 4020 enum qca_wlan_ac_type ac = QCA_WLAN_AC_BE; 4021 4022 pSession = &sme_qos_cb.sessionInfo[sessionId]; 4023 if (((SME_QOS_INIT == pSession->ac_info[QCA_WLAN_AC_BE].curr_state) 4024 && (SME_QOS_INIT == 4025 pSession->ac_info[QCA_WLAN_AC_BK].curr_state) 4026 && (SME_QOS_INIT == 4027 pSession->ac_info[QCA_WLAN_AC_VI].curr_state) 4028 && (SME_QOS_INIT == 4029 pSession->ac_info[QCA_WLAN_AC_VO].curr_state)) 4030 || (pSession->handoffRequested)) { 4031 /* get the association info */ 4032 if (!pEvent_info) { 4033 /* err msg */ 4034 sme_err("pEvent_info is NULL"); 4035 return status; 4036 } 4037 if (!((sme_QosAssocInfo *)pEvent_info)->bss_desc) { 4038 /* err msg */ 4039 sme_err("bss_desc is NULL"); 4040 return status; 4041 } 4042 if ((pSession->assocInfo.bss_desc) && 4043 (csr_is_bssid_match 4044 ((struct qdf_mac_addr *) 4045 &pSession->assocInfo.bss_desc->bssId, 4046 (struct qdf_mac_addr *) &(((sme_QosAssocInfo *) 4047 pEvent_info)->bss_desc->bssId)))) { 4048 sme_err("assoc with the same BSS, no update needed"); 4049 } else 4050 status = sme_qos_save_assoc_info(pSession, pEvent_info); 4051 } else { 4052 sme_err("wrong state: BE %d, BK %d, VI %d, VO %d", 4053 pSession->ac_info[QCA_WLAN_AC_BE].curr_state, 4054 pSession->ac_info[QCA_WLAN_AC_BK].curr_state, 4055 pSession->ac_info[QCA_WLAN_AC_VI].curr_state, 4056 pSession->ac_info[QCA_WLAN_AC_VO].curr_state); 4057 return status; 4058 } 4059 /* the session is active */ 4060 pSession->sessionActive = true; 4061 if (pSession->handoffRequested) { 4062 pSession->handoffRequested = false; 4063 /* renew all flows */ 4064 (void)sme_qos_process_buffered_cmd(sessionId); 4065 status = QDF_STATUS_SUCCESS; 4066 } else { 4067 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 4068 pACInfo = &pSession->ac_info[ac]; 4069 switch (pACInfo->curr_state) { 4070 case SME_QOS_INIT: 4071 sme_qos_state_transition(sessionId, ac, 4072 SME_QOS_LINK_UP); 4073 break; 4074 case SME_QOS_LINK_UP: 4075 case SME_QOS_REQUESTED: 4076 case SME_QOS_QOS_ON: 4077 case SME_QOS_HANDOFF: 4078 case SME_QOS_CLOSED: 4079 default: 4080 sme_err("On session %d AC %d is in wrong state %d", 4081 sessionId, ac, 4082 pACInfo->curr_state); 4083 break; 4084 } 4085 } 4086 } 4087 return status; 4088 } 4089 4090 /* 4091 * sme_qos_process_reassoc_req_ev() - Function to process the 4092 * SME_QOS_CSR_REASSOC_REQ event indication from CSR 4093 * 4094 * pEvent_info - Pointer to relevant info from CSR. 4095 * 4096 * Return QDF_STATUS 4097 */ 4098 static QDF_STATUS sme_qos_process_reassoc_req_ev(struct mac_context *mac, uint8_t 4099 sessionId, void *pEvent_info) 4100 { 4101 struct sme_qos_sessioninfo *pSession; 4102 struct sme_qos_acinfo *pACInfo; 4103 enum qca_wlan_ac_type ac; 4104 struct sme_qos_flowinfoentry *flow_info = NULL; 4105 tListElem *entry = NULL; 4106 4107 pSession = &sme_qos_cb.sessionInfo[sessionId]; 4108 4109 if (pSession->ftHandoffInProgress) { 4110 sme_debug("no need for state transition, should already be in handoff state"); 4111 if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || 4112 (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || 4113 (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || 4114 (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { 4115 sme_err("curr_state is not HANDOFF, session %d", 4116 sessionId); 4117 return QDF_STATUS_E_FAILURE; 4118 } 4119 sme_qos_process_ft_reassoc_req_ev(sessionId); 4120 return QDF_STATUS_SUCCESS; 4121 } 4122 4123 if (pSession->handoffRequested) { 4124 sme_debug("no need for state transition, should already be in handoff state"); 4125 4126 if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || 4127 (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || 4128 (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || 4129 (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { 4130 sme_err("curr_state is not HANDOFF, session %d", 4131 sessionId); 4132 return QDF_STATUS_E_FAILURE; 4133 } 4134 4135 /* 4136 * Now change reason and HO renewal of 4137 * all the flow in this session only 4138 */ 4139 entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 4140 if (!entry) { 4141 sme_debug("Flow List empty, nothing to update"); 4142 return QDF_STATUS_E_FAILURE; 4143 } 4144 4145 do { 4146 flow_info = GET_BASE_ADDR(entry, struct sme_qos_flowinfoentry, 4147 link); 4148 if (sessionId == flow_info->sessionId) { 4149 sme_info("Changing FlowID %d reason toSETUP and HO renewal to true", 4150 flow_info->QosFlowID); 4151 flow_info->reason = SME_QOS_REASON_SETUP; 4152 flow_info->hoRenewal = true; 4153 } 4154 entry = csr_ll_next(&sme_qos_cb.flow_list, entry, 4155 false); 4156 } while (entry); 4157 4158 /* buffer the existing flows to be renewed after handoff is 4159 * done 4160 */ 4161 sme_qos_buffer_existing_flows(mac, sessionId); 4162 /* clean up the control block partially for handoff */ 4163 sme_qos_cleanup_ctrl_blk_for_handoff(mac, sessionId); 4164 return QDF_STATUS_SUCCESS; 4165 } 4166 /* TBH: Assuming both handoff algo & 11r willn't be enabled at the same time */ 4167 if (pSession->ftHandoffInProgress) { 4168 sme_debug("no need for state transition, should already be in handoff state"); 4169 4170 if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || 4171 (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || 4172 (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || 4173 (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { 4174 sme_err("curr_state is not HANDOFF, session %d", 4175 sessionId); 4176 return QDF_STATUS_E_FAILURE; 4177 } 4178 4179 sme_qos_process_ft_reassoc_req_ev(sessionId); 4180 return QDF_STATUS_SUCCESS; 4181 } 4182 4183 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 4184 pACInfo = &pSession->ac_info[ac]; 4185 switch (pACInfo->curr_state) { 4186 case SME_QOS_LINK_UP: 4187 case SME_QOS_REQUESTED: 4188 case SME_QOS_QOS_ON: 4189 sme_qos_state_transition(sessionId, ac, 4190 SME_QOS_HANDOFF); 4191 break; 4192 case SME_QOS_HANDOFF: 4193 /* This is normal because sme_qos_request_reassoc may 4194 * already change the state 4195 */ 4196 break; 4197 case SME_QOS_CLOSED: 4198 case SME_QOS_INIT: 4199 default: 4200 sme_err("On session %d AC %d is in wrong state %d", 4201 sessionId, ac, pACInfo->curr_state); 4202 break; 4203 } 4204 } 4205 return QDF_STATUS_SUCCESS; 4206 } 4207 4208 /** 4209 * sme_qos_handle_handoff_state() - utility function called by 4210 * sme_qos_process_reassoc_success_ev 4211 * @mac_ctx: global MAC context 4212 * @qos_session: QOS session 4213 * @ac_info: AC information 4214 * @ac: current AC index 4215 * @sessionid: session id 4216 * 4217 * This function is called by sme_qos_process_reassoc_success_ev 4218 * to update the state machine on the reception of reassoc success 4219 * notification 4220 * 4221 * Return: QDF_STATUS 4222 */ 4223 static 4224 QDF_STATUS sme_qos_handle_handoff_state(struct mac_context *mac_ctx, 4225 struct sme_qos_sessioninfo *qos_session, 4226 struct sme_qos_acinfo *ac_info, 4227 enum qca_wlan_ac_type ac, uint8_t sessionid) 4228 4229 { 4230 struct sme_qos_searchinfo search_key; 4231 struct sme_qos_searchinfo search_key1; 4232 enum qca_wlan_ac_type ac_index; 4233 tListElem *list_elt = NULL; 4234 struct sme_qos_flowinfoentry *flow_info = NULL; 4235 QDF_STATUS status = QDF_STATUS_E_FAILURE; 4236 4237 /* return to our previous state */ 4238 sme_qos_state_transition(sessionid, ac, ac_info->prev_state); 4239 /* for which ac APSD (hence the reassoc) is requested */ 4240 if (!ac_info->reassoc_pending) 4241 return QDF_STATUS_SUCCESS; 4242 4243 /* 4244 * update the apsd mask in CB - make sure to take care of the 4245 * case where we are resetting the bit in apsd_mask 4246 */ 4247 if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb) 4248 qos_session->apsdMask |= 1 << (QCA_WLAN_AC_VO - ac); 4249 else 4250 qos_session->apsdMask &= ~(1 << (QCA_WLAN_AC_VO - ac)); 4251 4252 ac_info->reassoc_pending = false; 4253 /* 4254 * during setup it gets set as addts & reassoc both gets a 4255 * pending flag ac_info->tspec_pending = 0; 4256 */ 4257 sme_qos_state_transition(sessionid, ac, SME_QOS_QOS_ON); 4258 /* notify HDD with new Service Interval */ 4259 ac_info->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = 4260 ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]; 4261 qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); 4262 /* set the key type & the key to be searched in the Flow List */ 4263 search_key.key.ac_type = ac; 4264 search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; 4265 search_key.sessionId = sessionid; 4266 /* notify PMC that reassoc is done for APSD on certain AC?? */ 4267 4268 qdf_mem_zero(&search_key1, sizeof(struct sme_qos_searchinfo)); 4269 /* set the hoRenewal field in control block if needed */ 4270 search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3; 4271 search_key1.key.reason = SME_QOS_REASON_SETUP; 4272 search_key1.sessionId = sessionid; 4273 for (ac_index = QCA_WLAN_AC_BE; ac_index < QCA_WLAN_AC_ALL; 4274 ac_index++) { 4275 list_elt = sme_qos_find_in_flow_list(search_key1); 4276 if (list_elt) { 4277 flow_info = GET_BASE_ADDR(list_elt, 4278 struct sme_qos_flowinfoentry, link); 4279 if (flow_info->ac_type == ac) { 4280 ac_info->hoRenewal = flow_info->hoRenewal; 4281 break; 4282 } 4283 } 4284 } 4285 /* 4286 * notify HDD the success for the requested flow notify all the 4287 * other flows running on the AC that QoS got modified 4288 */ 4289 status = sme_qos_find_all_in_flow_list(mac_ctx, search_key, 4290 sme_qos_reassoc_success_ev_fnp); 4291 if (!QDF_IS_STATUS_SUCCESS(status)) { 4292 sme_err("no match found for ac = %d", search_key.key.ac_type); 4293 return QDF_STATUS_E_FAILURE; 4294 } 4295 ac_info->hoRenewal = false; 4296 qdf_mem_zero(&ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], 4297 sizeof(struct sme_qos_wmmtspecinfo)); 4298 4299 return status; 4300 } 4301 4302 /** 4303 * sme_qos_process_reassoc_success_ev() - process SME_QOS_CSR_REASSOC_COMPLETE 4304 * 4305 * @mac_ctx: global MAC context 4306 * @sessionid: session ID 4307 * @event_info: event buffer from CSR 4308 * 4309 * Function to process the SME_QOS_CSR_REASSOC_COMPLETE event indication 4310 * from CSR 4311 * 4312 * Return: QDF_STATUS 4313 */ 4314 static QDF_STATUS sme_qos_process_reassoc_success_ev(struct mac_context *mac_ctx, 4315 uint8_t sessionid, void *event_info) 4316 { 4317 4318 struct csr_roam_session *csr_roam_session = NULL; 4319 struct sme_qos_sessioninfo *qos_session; 4320 struct sme_qos_acinfo *ac_info; 4321 enum qca_wlan_ac_type ac; 4322 QDF_STATUS status = QDF_STATUS_E_FAILURE; 4323 4324 if (sessionid >= WLAN_MAX_VDEVS) { 4325 sme_err("invoked on session %d", sessionid); 4326 return status; 4327 } 4328 4329 csr_roam_session = CSR_GET_SESSION(mac_ctx, sessionid); 4330 4331 qos_session = &sme_qos_cb.sessionInfo[sessionid]; 4332 4333 /* get the association info */ 4334 if (!event_info) { 4335 sme_err("event_info is NULL"); 4336 return status; 4337 } 4338 4339 if (!((sme_QosAssocInfo *)event_info)->bss_desc) { 4340 sme_err("bss_desc is NULL"); 4341 return status; 4342 } 4343 status = sme_qos_save_assoc_info(qos_session, event_info); 4344 if (status) 4345 sme_err("sme_qos_save_assoc_info() failed"); 4346 4347 /* 4348 * Assuming both handoff algo & 11r willn't be enabled 4349 * at the same time 4350 */ 4351 if (qos_session->handoffRequested) { 4352 qos_session->handoffRequested = false; 4353 /* renew all flows */ 4354 (void)sme_qos_process_buffered_cmd(sessionid); 4355 return QDF_STATUS_SUCCESS; 4356 } 4357 if (qos_session->ftHandoffInProgress) { 4358 if (csr_roam_is11r_assoc(mac_ctx, sessionid)) { 4359 if (csr_roam_session && 4360 csr_roam_session->connectedInfo.nRICRspLength) { 4361 status = sme_qos_process_ft_reassoc_rsp_ev( 4362 mac_ctx, sessionid, 4363 event_info); 4364 } else { 4365 sme_debug("session or RIC data is not present"); 4366 } 4367 } 4368 #ifdef FEATURE_WLAN_ESE 4369 /* 4370 * If ESE association check for TSPEC IEs in the 4371 * reassoc rsp frame 4372 */ 4373 if (csr_roam_is_ese_assoc(mac_ctx, sessionid)) { 4374 if (csr_roam_session && 4375 csr_roam_session->connectedInfo.nTspecIeLength) { 4376 status = sme_qos_ese_process_reassoc_tspec_rsp( 4377 mac_ctx, sessionid, event_info); 4378 } 4379 } 4380 #endif 4381 qos_session->ftHandoffInProgress = false; 4382 qos_session->handoffRequested = false; 4383 return status; 4384 } 4385 4386 qos_session->sessionActive = true; 4387 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 4388 ac_info = &qos_session->ac_info[ac]; 4389 switch (ac_info->curr_state) { 4390 case SME_QOS_HANDOFF: 4391 status = sme_qos_handle_handoff_state(mac_ctx, 4392 qos_session, ac_info, ac, sessionid); 4393 break; 4394 case SME_QOS_INIT: 4395 case SME_QOS_CLOSED: 4396 /* NOP */ 4397 status = QDF_STATUS_SUCCESS; 4398 break; 4399 case SME_QOS_LINK_UP: 4400 case SME_QOS_REQUESTED: 4401 case SME_QOS_QOS_ON: 4402 default: 4403 sme_err("session %d AC %d is in wrong state %d", 4404 sessionid, ac, ac_info->curr_state); 4405 break; 4406 } 4407 } 4408 (void)sme_qos_process_buffered_cmd(sessionid); 4409 return status; 4410 } 4411 4412 /* 4413 * sme_qos_process_reassoc_failure_ev() - Function to process the 4414 * SME_QOS_CSR_REASSOC_FAILURE event indication from CSR 4415 * 4416 * pEvent_info - Pointer to relevant info from CSR. 4417 * 4418 * Return QDF_STATUS 4419 */ 4420 static QDF_STATUS sme_qos_process_reassoc_failure_ev(struct mac_context *mac, 4421 uint8_t sessionId, void *pEvent_info) 4422 { 4423 struct sme_qos_sessioninfo *pSession; 4424 struct sme_qos_acinfo *pACInfo; 4425 enum qca_wlan_ac_type ac; 4426 4427 pSession = &sme_qos_cb.sessionInfo[sessionId]; 4428 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 4429 pACInfo = &pSession->ac_info[ac]; 4430 switch (pACInfo->curr_state) { 4431 case SME_QOS_HANDOFF: 4432 sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); 4433 if (pACInfo->reassoc_pending) 4434 pACInfo->reassoc_pending = false; 4435 4436 qdf_mem_zero(&pACInfo-> 4437 curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], 4438 sizeof(struct sme_qos_wmmtspecinfo)); 4439 qdf_mem_zero(&pACInfo-> 4440 requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], 4441 sizeof(struct sme_qos_wmmtspecinfo)); 4442 qdf_mem_zero(&pACInfo-> 4443 curr_QoSInfo[SME_QOS_TSPEC_INDEX_1], 4444 sizeof(struct sme_qos_wmmtspecinfo)); 4445 qdf_mem_zero(&pACInfo-> 4446 requested_QoSInfo[SME_QOS_TSPEC_INDEX_1], 4447 sizeof(struct sme_qos_wmmtspecinfo)); 4448 pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR; 4449 pACInfo->tspec_pending = 0; 4450 pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] = 0; 4451 pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] = 0; 4452 break; 4453 case SME_QOS_INIT: 4454 case SME_QOS_CLOSED: 4455 /* NOP */ 4456 break; 4457 case SME_QOS_LINK_UP: 4458 case SME_QOS_REQUESTED: 4459 case SME_QOS_QOS_ON: 4460 default: 4461 sme_err("On session %d AC %d is in wrong state %d", 4462 sessionId, ac, pACInfo->curr_state); 4463 break; 4464 } 4465 } 4466 /* need to clean up flows */ 4467 sme_qos_delete_existing_flows(mac, sessionId); 4468 return QDF_STATUS_SUCCESS; 4469 } 4470 4471 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 4472 #ifdef FEATURE_WLAN_ESE 4473 static bool sme_qos_ft_handoff_required(struct mac_context *mac, 4474 uint8_t session_id) 4475 { 4476 struct csr_roam_session *csr_roam_session; 4477 4478 if (csr_roam_is11r_assoc(mac, session_id)) 4479 return true; 4480 4481 csr_roam_session = CSR_GET_SESSION(mac, session_id); 4482 4483 if (csr_roam_session && 4484 wlan_cm_is_roam_sync_in_progress(mac->psoc, session_id) && 4485 csr_roam_is_ese_assoc(mac, session_id) && 4486 csr_roam_session->connectedInfo.nTspecIeLength) 4487 return true; 4488 4489 return false; 4490 } 4491 #else 4492 static inline bool sme_qos_ft_handoff_required(struct mac_context *mac, 4493 uint8_t session_id) 4494 { 4495 return csr_roam_is11r_assoc(mac, session_id) ? true : false; 4496 } 4497 #endif 4498 #else 4499 static inline bool sme_qos_ft_handoff_required(struct mac_context *mac, 4500 uint8_t session_id) 4501 { 4502 return false; 4503 } 4504 #endif 4505 4506 #ifdef FEATURE_WLAN_ESE 4507 static inline bool sme_qos_legacy_handoff_required(struct mac_context *mac, 4508 uint8_t session_id) 4509 { 4510 return csr_roam_is_ese_assoc(mac, session_id) ? false : true; 4511 } 4512 #else 4513 static inline bool sme_qos_legacy_handoff_required(struct mac_context *mac, 4514 uint8_t session_id) 4515 { 4516 return true; 4517 } 4518 #endif 4519 4520 /* 4521 * sme_qos_process_handoff_assoc_req_ev() - Function to process the 4522 * SME_QOS_CSR_HANDOFF_ASSOC_REQ event indication from CSR 4523 * 4524 * pEvent_info - Pointer to relevant info from CSR. 4525 * 4526 * Return QDF_STATUS 4527 */ 4528 static QDF_STATUS sme_qos_process_handoff_assoc_req_ev(struct mac_context *mac, 4529 uint8_t sessionId, void *pEvent_info) 4530 { 4531 struct sme_qos_sessioninfo *pSession; 4532 struct sme_qos_acinfo *pACInfo; 4533 uint8_t ac; 4534 4535 pSession = &sme_qos_cb.sessionInfo[sessionId]; 4536 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 4537 pACInfo = &pSession->ac_info[ac]; 4538 switch (pACInfo->curr_state) { 4539 case SME_QOS_LINK_UP: 4540 case SME_QOS_REQUESTED: 4541 case SME_QOS_QOS_ON: 4542 sme_qos_state_transition(sessionId, ac, 4543 SME_QOS_HANDOFF); 4544 break; 4545 case SME_QOS_HANDOFF: 4546 /* print error msg */ 4547 if (pSession->ftHandoffInProgress) { 4548 sme_debug("SME_QOS_CSR_HANDOFF_ASSOC_REQ received in SME_QOS_HANDOFF state with FT in progress"); 4549 break; 4550 } 4551 fallthrough; 4552 case SME_QOS_CLOSED: 4553 case SME_QOS_INIT: 4554 default: 4555 sme_err("On session %d AC %d is in wrong state %d", 4556 sessionId, ac, pACInfo->curr_state); 4557 break; 4558 } 4559 } 4560 4561 if (sme_qos_ft_handoff_required(mac, sessionId)) 4562 pSession->ftHandoffInProgress = true; 4563 4564 /* If FT handoff/ESE in progress, legacy handoff need not be enabled */ 4565 if (!pSession->ftHandoffInProgress && 4566 sme_qos_legacy_handoff_required(mac, sessionId)) 4567 pSession->handoffRequested = true; 4568 4569 /* this session no longer needs UAPSD */ 4570 pSession->apsdMask = 0; 4571 /* do any sessions still require UAPSD? */ 4572 sme_ps_uapsd_disable(MAC_HANDLE(mac), sessionId); 4573 return QDF_STATUS_SUCCESS; 4574 } 4575 4576 /* 4577 * sme_qos_process_handoff_success_ev() - Function to process the 4578 * SME_QOS_CSR_HANDOFF_COMPLETE event indication from CSR 4579 * 4580 * pEvent_info - Pointer to relevant info from CSR. 4581 * 4582 * Return QDF_STATUS 4583 */ 4584 static QDF_STATUS sme_qos_process_handoff_success_ev(struct mac_context *mac, 4585 uint8_t sessionId, void *pEvent_info) 4586 { 4587 struct sme_qos_sessioninfo *pSession; 4588 struct sme_qos_acinfo *pACInfo; 4589 uint8_t ac; 4590 QDF_STATUS status = QDF_STATUS_E_FAILURE; 4591 4592 pSession = &sme_qos_cb.sessionInfo[sessionId]; 4593 /* go back to original state before handoff */ 4594 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 4595 pACInfo = &pSession->ac_info[ac]; 4596 switch (pACInfo->curr_state) { 4597 case SME_QOS_HANDOFF: 4598 sme_qos_state_transition(sessionId, ac, 4599 pACInfo->prev_state); 4600 /* we will retry for the requested flow(s) with the 4601 * new AP 4602 */ 4603 if (SME_QOS_REQUESTED == pACInfo->curr_state) 4604 pACInfo->curr_state = SME_QOS_LINK_UP; 4605 4606 status = QDF_STATUS_SUCCESS; 4607 break; 4608 /* FT logic, has already moved it to QOS_REQUESTED state during 4609 * the reassoc request event, which would include the Qos 4610 * (TSPEC) params in the reassoc req frame 4611 */ 4612 case SME_QOS_REQUESTED: 4613 break; 4614 case SME_QOS_INIT: 4615 case SME_QOS_CLOSED: 4616 case SME_QOS_LINK_UP: 4617 case SME_QOS_QOS_ON: 4618 default: 4619 /* In case of 11r - RIC, we request QoS and Hand-off at the same time hence the 4620 * state may be SME_QOS_REQUESTED 4621 */ 4622 if (pSession->ftHandoffInProgress) 4623 break; 4624 sme_err("On session %d AC %d is in wrong state %d", 4625 sessionId, ac, pACInfo->curr_state); 4626 break; 4627 } 4628 } 4629 return status; 4630 } 4631 4632 /* 4633 * sme_qos_process_disconnect_ev() - Function to process the 4634 * SME_QOS_CSR_DISCONNECT_REQ or SME_QOS_CSR_DISCONNECT_IND event indication 4635 * from CSR 4636 * 4637 * pEvent_info - Pointer to relevant info from CSR. 4638 * 4639 * Return QDF_STATUS 4640 */ 4641 static QDF_STATUS sme_qos_process_disconnect_ev(struct mac_context *mac, uint8_t 4642 sessionId, void *pEvent_info) 4643 { 4644 struct sme_qos_sessioninfo *pSession; 4645 4646 pSession = &sme_qos_cb.sessionInfo[sessionId]; 4647 /* 4648 * In case of 11r - RIC, we request QoS and Hand-off at the 4649 * same time hence the state may be SME_QOS_REQUESTED 4650 */ 4651 if ((pSession->handoffRequested) 4652 && !pSession->ftHandoffInProgress) { 4653 sme_debug("no need for state transition, should already be in handoff state"); 4654 if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || 4655 (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || 4656 (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || 4657 (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { 4658 sme_err("curr_state is not HANDOFF, session %d", 4659 sessionId); 4660 return QDF_STATUS_SUCCESS; 4661 } 4662 4663 return QDF_STATUS_SUCCESS; 4664 } 4665 sme_qos_init_a_cs(mac, sessionId); 4666 /* this session doesn't require UAPSD */ 4667 pSession->apsdMask = 0; 4668 4669 sme_ps_uapsd_disable(MAC_HANDLE(mac), sessionId); 4670 4671 pSession->handoffRequested = false; 4672 pSession->roamID = 0; 4673 /* need to clean up buffered req */ 4674 sme_qos_delete_buffered_requests(mac, sessionId); 4675 /* need to clean up flows */ 4676 sme_qos_delete_existing_flows(mac, sessionId); 4677 /* clean up the assoc info */ 4678 if (pSession->assocInfo.bss_desc) { 4679 qdf_mem_free(pSession->assocInfo.bss_desc); 4680 pSession->assocInfo.bss_desc = NULL; 4681 } 4682 sme_qos_cb.sessionInfo[sessionId].sessionActive = false; 4683 return QDF_STATUS_SUCCESS; 4684 } 4685 4686 /* 4687 * sme_qos_process_join_req_ev() - Function to process the 4688 * SME_QOS_CSR_JOIN_REQ event indication from CSR 4689 * 4690 * pEvent_info - Pointer to relevant info from CSR. 4691 * 4692 * Return QDF_STATUS 4693 */ 4694 static QDF_STATUS sme_qos_process_join_req_ev(struct mac_context *mac, uint8_t 4695 sessionId, void *pEvent_info) 4696 { 4697 struct sme_qos_sessioninfo *pSession; 4698 enum qca_wlan_ac_type ac; 4699 4700 pSession = &sme_qos_cb.sessionInfo[sessionId]; 4701 if (pSession->handoffRequested) { 4702 sme_debug("No need for state transition, should already be in handoff state"); 4703 if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || 4704 (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || 4705 (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || 4706 (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) 4707 sme_err("curr_state is not HANDOFF, session %d", 4708 sessionId); 4709 /* buffer the existing flows to be renewed after handoff is 4710 * done 4711 */ 4712 sme_qos_buffer_existing_flows(mac, sessionId); 4713 /* clean up the control block partially for handoff */ 4714 sme_qos_cleanup_ctrl_blk_for_handoff(mac, sessionId); 4715 return QDF_STATUS_SUCCESS; 4716 } 4717 4718 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) 4719 sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); 4720 4721 /* clean up the assoc info if already set */ 4722 if (pSession->assocInfo.bss_desc) { 4723 qdf_mem_free(pSession->assocInfo.bss_desc); 4724 pSession->assocInfo.bss_desc = NULL; 4725 } 4726 return QDF_STATUS_SUCCESS; 4727 } 4728 4729 #ifdef WLAN_FEATURE_HOST_ROAM 4730 /** 4731 * sme_qos_process_preauth_success_ind() - process preauth success indication 4732 * @mac_ctx: global MAC context 4733 * @sessionid: session ID 4734 * @event_info: event buffer 4735 * 4736 * Function to process the SME_QOS_CSR_PREAUTH_SUCCESS_IND event indication 4737 * from CSR 4738 * 4739 * Return: QDF_STATUS 4740 */ 4741 static QDF_STATUS sme_qos_process_preauth_success_ind(struct mac_context *mac_ctx, 4742 uint8_t sessionid, void *event_info) 4743 { 4744 struct sme_qos_sessioninfo *qos_session; 4745 struct csr_roam_session *sme_session = CSR_GET_SESSION(mac_ctx, 4746 sessionid); 4747 struct sme_qos_acinfo *ac_info; 4748 uint8_t ac; 4749 QDF_STATUS status = QDF_STATUS_SUCCESS; 4750 uint16_t ric_offset = 0; 4751 uint32_t ric_ielen = 0; 4752 uint8_t *ric_ie; 4753 uint8_t tspec_mask_status = 0; 4754 uint8_t tspec_pending_status = 0; 4755 struct wlan_objmgr_vdev *vdev; 4756 struct mlme_legacy_priv *mlme_priv; 4757 4758 if (!sme_session) { 4759 sme_err("sme_session is NULL"); 4760 return QDF_STATUS_E_INVAL; 4761 } 4762 4763 qos_session = &sme_qos_cb.sessionInfo[sessionid]; 4764 4765 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 4766 ac_info = &qos_session->ac_info[ac]; 4767 4768 switch (ac_info->curr_state) { 4769 case SME_QOS_LINK_UP: 4770 case SME_QOS_REQUESTED: 4771 case SME_QOS_QOS_ON: 4772 sme_qos_state_transition(sessionid, ac, SME_QOS_HANDOFF); 4773 break; 4774 case SME_QOS_HANDOFF: 4775 /* print error msg */ 4776 case SME_QOS_CLOSED: 4777 case SME_QOS_INIT: 4778 default: 4779 sme_err("Session %d AC %d is in wrong state %d", 4780 sessionid, ac, ac_info->curr_state); 4781 break; 4782 } 4783 } 4784 4785 qos_session->ftHandoffInProgress = true; 4786 4787 /* Check if its a 11R roaming before preparing the RIC IEs */ 4788 if (!csr_roam_is11r_assoc(mac_ctx, sessionid)) 4789 return status; 4790 4791 vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, sessionid, 4792 WLAN_LEGACY_SME_ID); 4793 if (!vdev) 4794 return QDF_STATUS_E_INVAL; 4795 mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); 4796 if (!mlme_priv) { 4797 status = QDF_STATUS_E_FAILURE; 4798 goto end; 4799 } 4800 4801 /* 4802 * Any Block Ack info there, should have been already filled by PE and 4803 * present in this buffer and the ric_ies_length should contain the 4804 * length of the whole RIC IEs. Filling of TSPEC info should start 4805 * from this length 4806 */ 4807 qdf_mem_zero(mlme_priv->connect_info.ft_info.ric_ies, MAX_FTIE_SIZE); 4808 mlme_priv->connect_info.ft_info.ric_ies_length = 0; 4809 4810 ric_ie = mlme_priv->connect_info.ft_info.ric_ies; 4811 ric_offset = mlme_priv->connect_info.ft_info.ric_ies_length; 4812 4813 /* 4814 * Now we have to process the currentTspeInfo inside this session and 4815 * create the RIC IEs 4816 */ 4817 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 4818 volatile uint8_t tspec_idx = 0; 4819 4820 ric_ielen = 0; 4821 ac_info = &qos_session->ac_info[ac]; 4822 tspec_pending_status = ac_info->tspec_pending; 4823 tspec_mask_status = ac_info->tspec_mask_status; 4824 qdf_mem_zero(ac_info->ricIdentifier, SME_QOS_TSPEC_INDEX_MAX); 4825 sme_debug("AC %d ==> TSPEC status = %d, tspec pending = %d", 4826 ac, tspec_mask_status, tspec_pending_status); 4827 4828 do { 4829 if (!(tspec_mask_status & 0x1)) 4830 goto add_next_ric; 4831 4832 /* 4833 * If a tspec status is pending, take requested_QoSInfo 4834 * for RIC request, else use curr_QoSInfo for the 4835 * RIC request 4836 */ 4837 if (tspec_pending_status & 0x1) { 4838 status = sme_qos_create_tspec_ricie(mac_ctx, 4839 &ac_info->requested_QoSInfo[tspec_idx], 4840 ric_ie + ric_offset, &ric_ielen, 4841 &ac_info->ricIdentifier[tspec_idx]); 4842 } else { 4843 status = sme_qos_create_tspec_ricie(mac_ctx, 4844 &ac_info->curr_QoSInfo[tspec_idx], 4845 ric_ie + ric_offset, &ric_ielen, 4846 &ac_info->ricIdentifier[tspec_idx]); 4847 } 4848 add_next_ric: 4849 ric_offset += ric_ielen; 4850 mlme_priv->connect_info.ft_info.ric_ies_length = ric_ielen; 4851 tspec_mask_status >>= 1; 4852 tspec_pending_status >>= 1; 4853 tspec_idx++; 4854 } while (tspec_mask_status); 4855 } 4856 end: 4857 wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); 4858 4859 return status; 4860 } 4861 #else 4862 static inline 4863 QDF_STATUS sme_qos_process_preauth_success_ind(struct mac_context *mac_ctx, 4864 uint8_t sessionid, void *event_info) 4865 { 4866 return QDF_STATUS_SUCCESS; 4867 } 4868 #endif 4869 /* 4870 * sme_qos_process_add_ts_failure_rsp() - Function to process the 4871 * Addts request failure response came from PE 4872 * 4873 * We will notify HDD only for the requested Flow, other Flows running on the AC 4874 * stay intact 4875 * 4876 * mac - Pointer to the global MAC parameter structure. 4877 * pRsp - Pointer to the addts response structure came from PE. 4878 * 4879 * Return QDF_STATUS 4880 */ 4881 static QDF_STATUS sme_qos_process_add_ts_failure_rsp(struct mac_context *mac, 4882 uint8_t sessionId, 4883 tSirAddtsRspInfo *pRsp) 4884 { 4885 struct sme_qos_sessioninfo *pSession; 4886 struct sme_qos_acinfo *pACInfo; 4887 enum qca_wlan_ac_type ac; 4888 struct sme_qos_searchinfo search_key; 4889 uint8_t tspec_pending; 4890 enum sme_qos_wmmuptype up = 4891 (enum sme_qos_wmmuptype) pRsp->tspec.tsinfo.traffic.userPrio; 4892 4893 sme_debug("invoked on session %d for UP %d", sessionId, up); 4894 ac = sme_qos_up_to_ac(up); 4895 if (QCA_WLAN_AC_ALL == ac) { 4896 /* err msg */ 4897 sme_err("invalid AC %d from UP %d", ac, up); 4898 return QDF_STATUS_E_FAILURE; 4899 } 4900 pSession = &sme_qos_cb.sessionInfo[sessionId]; 4901 pACInfo = &pSession->ac_info[ac]; 4902 /* is there a TSPEC request pending on this AC? */ 4903 tspec_pending = pACInfo->tspec_pending; 4904 if (!tspec_pending) { 4905 sme_err("On session %d an AddTS is not pending on AC %d", 4906 sessionId, ac); 4907 return QDF_STATUS_E_FAILURE; 4908 } 4909 4910 qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); 4911 /* set the key type & the key to be searched in the Flow List */ 4912 search_key.key.ac_type = ac; 4913 search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; 4914 search_key.sessionId = sessionId; 4915 if (!QDF_IS_STATUS_SUCCESS 4916 (sme_qos_find_all_in_flow_list 4917 (mac, search_key, sme_qos_add_ts_failure_fnp))) { 4918 sme_err("On session %d no match found for ac = %d", 4919 sessionId, search_key.key.ac_type); 4920 return QDF_STATUS_E_FAILURE; 4921 } 4922 qdf_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1], 4923 sizeof(struct sme_qos_wmmtspecinfo)); 4924 4925 if ((!pACInfo->num_flows[0]) && (!pACInfo->num_flows[1])) { 4926 pACInfo->tspec_mask_status &= SME_QOS_TSPEC_MASK_BIT_1_2_SET & 4927 (~pACInfo->tspec_pending); 4928 sme_qos_state_transition(sessionId, ac, SME_QOS_LINK_UP); 4929 } else 4930 sme_qos_state_transition(sessionId, ac, SME_QOS_QOS_ON); 4931 4932 pACInfo->tspec_pending = 0; 4933 4934 (void)sme_qos_process_buffered_cmd(sessionId); 4935 4936 return QDF_STATUS_SUCCESS; 4937 } 4938 4939 /** 4940 * sme_qos_update_tspec_mask() - Utility function to update the tspec. 4941 * @sessionid: Session upon which the TSPEC is being updated 4942 * @search_key: search key 4943 * @new_tspec_mask: tspec to be set for this AC 4944 * 4945 * Typical usage while aggregating unidirectional flows into a bi-directional 4946 * flow on AC which is running multiple flows 4947 * 4948 * Return: QDF_STATUS 4949 */ 4950 static QDF_STATUS sme_qos_update_tspec_mask(uint8_t sessionid, 4951 struct sme_qos_searchinfo 4952 search_key, 4953 uint8_t new_tspec_mask) 4954 { 4955 tListElem *list_elt = NULL, *list_next_elt = NULL; 4956 struct sme_qos_flowinfoentry *flow_info = NULL; 4957 struct sme_qos_sessioninfo *qos_session; 4958 struct sme_qos_acinfo *ac_info; 4959 4960 sme_debug("invoked on session %d for AC %d TSPEC %d", 4961 sessionid, search_key.key.ac_type, new_tspec_mask); 4962 4963 qos_session = &sme_qos_cb.sessionInfo[sessionid]; 4964 4965 if (search_key.key.ac_type < QCA_WLAN_AC_ALL) { 4966 ac_info = &qos_session->ac_info[search_key.key.ac_type]; 4967 } else { 4968 sme_debug("Exceeded the array bounds"); 4969 return QDF_STATUS_E_FAILURE; 4970 } 4971 4972 list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 4973 if (!list_elt) { 4974 sme_err("Flow List empty, nothing to update"); 4975 return QDF_STATUS_E_FAILURE; 4976 } 4977 4978 while (list_elt) { 4979 list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, 4980 false); 4981 flow_info = GET_BASE_ADDR(list_elt, struct 4982 sme_qos_flowinfoentry, link); 4983 4984 if (search_key.sessionId != flow_info->sessionId) { 4985 list_elt = list_next_elt; 4986 continue; 4987 } 4988 4989 if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_4) { 4990 if ((search_key.key.ac_type == flow_info->ac_type) && 4991 (search_key.direction == 4992 flow_info->QoSInfo.ts_info.direction)) { 4993 sme_debug("Flow %d matches", 4994 flow_info->QosFlowID); 4995 ac_info->num_flows[flow_info->tspec_mask - 1]--; 4996 ac_info->num_flows[new_tspec_mask - 1]++; 4997 flow_info->tspec_mask = new_tspec_mask; 4998 } 4999 } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_5) { 5000 if ((search_key.key.ac_type == flow_info->ac_type) && 5001 (search_key.tspec_mask == flow_info->tspec_mask)) { 5002 sme_debug("Flow %d matches", 5003 flow_info->QosFlowID); 5004 ac_info->num_flows[flow_info->tspec_mask - 1]--; 5005 ac_info->num_flows[new_tspec_mask - 1]++; 5006 flow_info->tspec_mask = new_tspec_mask; 5007 } 5008 } 5009 list_elt = list_next_elt; 5010 } 5011 5012 return QDF_STATUS_SUCCESS; 5013 } 5014 5015 /* 5016 * sme_qos_process_add_ts_success_rsp() - Function to process the 5017 * Addts request success response came from PE 5018 * 5019 * We will notify HDD with addts success for the requested Flow, & for other 5020 * Flows running on the AC we will send an addts modify status 5021 * 5022 * mac - Pointer to the global MAC parameter structure. 5023 * pRsp - Pointer to the addts response structure came from PE. 5024 * 5025 * Return QDF_STATUS 5026 */ 5027 static QDF_STATUS sme_qos_process_add_ts_success_rsp(struct mac_context *mac, 5028 uint8_t sessionId, 5029 tSirAddtsRspInfo *pRsp) 5030 { 5031 struct sme_qos_sessioninfo *pSession; 5032 struct sme_qos_acinfo *pACInfo; 5033 enum qca_wlan_ac_type ac, ac_index; 5034 struct sme_qos_searchinfo search_key; 5035 struct sme_qos_searchinfo search_key1; 5036 uint8_t tspec_pending; 5037 tListElem *pEntry = NULL; 5038 enum QDF_OPMODE opmode; 5039 struct sme_qos_flowinfoentry *flow_info = NULL; 5040 enum sme_qos_wmmuptype up = 5041 (enum sme_qos_wmmuptype) pRsp->tspec.tsinfo.traffic.userPrio; 5042 #ifdef FEATURE_WLAN_DIAG_SUPPORT 5043 WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); 5044 host_log_qos_tspec_pkt_type *log_ptr = NULL; 5045 #endif /* FEATURE_WLAN_DIAG_SUPPORT */ 5046 5047 sme_debug("invoked on session %d for UP %d", sessionId, up); 5048 pSession = &sme_qos_cb.sessionInfo[sessionId]; 5049 ac = sme_qos_up_to_ac(up); 5050 if (QCA_WLAN_AC_ALL == ac) { 5051 /* err msg */ 5052 sme_err("invalid AC %d from UP %d", ac, up); 5053 return QDF_STATUS_E_FAILURE; 5054 } 5055 pACInfo = &pSession->ac_info[ac]; 5056 /* is there a TSPEC request pending on this AC? */ 5057 tspec_pending = pACInfo->tspec_pending; 5058 if (!tspec_pending) { 5059 sme_err("On session %d an AddTS is not pending on AC %d", 5060 sessionId, ac); 5061 return QDF_STATUS_E_FAILURE; 5062 } 5063 /* App is looking for APSD or the App which was looking for APSD has 5064 * been released, so STA re-negotiated with AP 5065 */ 5066 if (pACInfo->requested_QoSInfo[tspec_pending - 1].ts_info.psb) { 5067 /* update the session's apsd mask */ 5068 pSession->apsdMask |= 1 << (QCA_WLAN_AC_VO - ac); 5069 } else { 5070 if (((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) > 0) && 5071 ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) <= 5072 SME_QOS_TSPEC_INDEX_MAX)) { 5073 if (!pACInfo->requested_QoSInfo 5074 [(SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) - 5075 1].ts_info.psb) 5076 /* update the session's apsd mask */ 5077 pSession->apsdMask &= 5078 ~(1 << (QCA_WLAN_AC_VO - ac)); 5079 } else { 5080 sme_debug("Exceeded the array bounds of pACInfo->requested_QosInfo"); 5081 return QDF_STATUS_E_FAILURE; 5082 } 5083 } 5084 5085 pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.burst_size_defn = 5086 pRsp->tspec.tsinfo.traffic.burstSizeDefn; 5087 pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.ack_policy = 5088 pRsp->tspec.tsinfo.traffic.ackPolicy; 5089 pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.up = 5090 pRsp->tspec.tsinfo.traffic.userPrio; 5091 pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.psb = 5092 pRsp->tspec.tsinfo.traffic.psb; 5093 pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.direction = 5094 pRsp->tspec.tsinfo.traffic.direction; 5095 pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.tid = 5096 pRsp->tspec.tsinfo.traffic.tsid; 5097 pACInfo->curr_QoSInfo[tspec_pending - 1].nominal_msdu_size = 5098 pRsp->tspec.nomMsduSz; 5099 pACInfo->curr_QoSInfo[tspec_pending - 1].maximum_msdu_size = 5100 pRsp->tspec.maxMsduSz; 5101 pACInfo->curr_QoSInfo[tspec_pending - 1].min_service_interval = 5102 pRsp->tspec.minSvcInterval; 5103 pACInfo->curr_QoSInfo[tspec_pending - 1].max_service_interval = 5104 pRsp->tspec.maxSvcInterval; 5105 pACInfo->curr_QoSInfo[tspec_pending - 1].inactivity_interval = 5106 pRsp->tspec.inactInterval; 5107 pACInfo->curr_QoSInfo[tspec_pending - 1].suspension_interval = 5108 pRsp->tspec.suspendInterval; 5109 pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time = 5110 pRsp->tspec.svcStartTime; 5111 pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate = 5112 pRsp->tspec.minDataRate; 5113 pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate = 5114 pRsp->tspec.meanDataRate; 5115 pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate = 5116 pRsp->tspec.peakDataRate; 5117 pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size = 5118 pRsp->tspec.maxBurstSz; 5119 pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound = 5120 pRsp->tspec.delayBound; 5121 5122 pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate = 5123 pRsp->tspec.minPhyRate; 5124 pACInfo->curr_QoSInfo[tspec_pending - 1].surplus_bw_allowance = 5125 pRsp->tspec.surplusBw; 5126 pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time = 5127 pRsp->tspec.mediumTime; 5128 5129 sme_set_tspec_uapsd_mask_per_session(mac, 5130 &pRsp->tspec.tsinfo, sessionId); 5131 5132 sme_debug("On session %d AddTspec Medium Time %d", 5133 sessionId, pRsp->tspec.mediumTime); 5134 5135 /* Check if the current flow is for bi-directional. If so, update the 5136 * number of flows to reflect that all flows are aggregated into tspec 5137 * index 0. 5138 */ 5139 if ((pACInfo->curr_QoSInfo[pACInfo->tspec_pending - 1].ts_info. 5140 direction == SME_QOS_WMM_TS_DIR_BOTH) 5141 && (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0)) { 5142 qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); 5143 /* update tspec_mask for all the flows having 5144 * SME_QOS_TSPEC_MASK_BIT_2_SET to SME_QOS_TSPEC_MASK_BIT_1_SET 5145 */ 5146 search_key.key.ac_type = ac; 5147 search_key.index = SME_QOS_SEARCH_KEY_INDEX_5; 5148 search_key.sessionId = sessionId; 5149 search_key.tspec_mask = SME_QOS_TSPEC_MASK_BIT_2_SET; 5150 sme_qos_update_tspec_mask(sessionId, search_key, 5151 SME_QOS_TSPEC_MASK_BIT_1_SET); 5152 } 5153 5154 qdf_mem_zero(&search_key1, sizeof(struct sme_qos_searchinfo)); 5155 /* set the horenewal field in control block if needed */ 5156 search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3; 5157 search_key1.key.reason = SME_QOS_REASON_SETUP; 5158 search_key1.sessionId = sessionId; 5159 for (ac_index = QCA_WLAN_AC_BE; ac_index < QCA_WLAN_AC_ALL; 5160 ac_index++) { 5161 pEntry = sme_qos_find_in_flow_list(search_key1); 5162 if (pEntry) { 5163 flow_info = GET_BASE_ADDR(pEntry, 5164 struct sme_qos_flowinfoentry, link); 5165 if (flow_info->ac_type == ac) { 5166 pACInfo->hoRenewal = flow_info->hoRenewal; 5167 break; 5168 } 5169 } 5170 } 5171 qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); 5172 /* set the key type & the key to be searched in the Flow List */ 5173 search_key.key.ac_type = ac; 5174 search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; 5175 search_key.sessionId = sessionId; 5176 /* notify HDD the success for the requested flow */ 5177 /* notify all the other flows running on the AC that QoS got modified */ 5178 if (!QDF_IS_STATUS_SUCCESS 5179 (sme_qos_find_all_in_flow_list 5180 (mac, search_key, sme_qos_add_ts_success_fnp))) { 5181 sme_err("On session %d no match found for ac %d", sessionId, 5182 search_key.key.ac_type); 5183 return QDF_STATUS_E_FAILURE; 5184 } 5185 pACInfo->hoRenewal = false; 5186 qdf_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1], 5187 sizeof(struct sme_qos_wmmtspecinfo)); 5188 /* event: EVENT_WLAN_QOS */ 5189 #ifdef FEATURE_WLAN_DIAG_SUPPORT 5190 qos.eventId = SME_QOS_DIAG_ADDTS_RSP; 5191 qos.reasonCode = SME_QOS_DIAG_ADDTS_ADMISSION_ACCEPTED; 5192 WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); 5193 WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_tspec_pkt_type, 5194 LOG_WLAN_QOS_TSPEC_C); 5195 if (log_ptr) { 5196 log_ptr->delay_bound = 5197 pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound; 5198 log_ptr->inactivity_interval = 5199 pACInfo->curr_QoSInfo[tspec_pending - 5200 1].inactivity_interval; 5201 log_ptr->max_burst_size = 5202 pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size; 5203 log_ptr->max_service_interval = 5204 pACInfo->curr_QoSInfo[tspec_pending - 5205 1].max_service_interval; 5206 log_ptr->maximum_msdu_size = 5207 pACInfo->curr_QoSInfo[tspec_pending - 1]. 5208 maximum_msdu_size; 5209 log_ptr->mean_data_rate = 5210 pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate; 5211 log_ptr->medium_time = 5212 pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time; 5213 log_ptr->min_data_rate = 5214 pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate; 5215 log_ptr->min_phy_rate = 5216 pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate; 5217 log_ptr->min_service_interval = 5218 pACInfo->curr_QoSInfo[tspec_pending - 5219 1].min_service_interval; 5220 log_ptr->nominal_msdu_size = 5221 pACInfo->curr_QoSInfo[tspec_pending - 1]. 5222 nominal_msdu_size; 5223 log_ptr->peak_data_rate = 5224 pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate; 5225 log_ptr->surplus_bw_allowance = 5226 pACInfo->curr_QoSInfo[tspec_pending - 5227 1].surplus_bw_allowance; 5228 log_ptr->suspension_interval = 5229 pACInfo->curr_QoSInfo[tspec_pending - 5230 1].suspension_interval; 5231 log_ptr->svc_start_time = 5232 pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time; 5233 log_ptr->tsinfo[0] = 5234 pACInfo->curr_QoSInfo[tspec_pending - 5235 1].ts_info.direction << 5 | 5236 pACInfo-> 5237 curr_QoSInfo[tspec_pending - 1].ts_info.tid << 1; 5238 log_ptr->tsinfo[1] = 5239 pACInfo->curr_QoSInfo[tspec_pending - 5240 1].ts_info.up << 11 | pACInfo-> 5241 curr_QoSInfo[tspec_pending - 1].ts_info.psb << 10; 5242 log_ptr->tsinfo[2] = 0; 5243 } 5244 WLAN_HOST_DIAG_LOG_REPORT(log_ptr); 5245 #endif /* FEATURE_WLAN_DIAG_SUPPORT */ 5246 pACInfo->tspec_pending = 0; 5247 5248 sme_qos_state_transition(sessionId, ac, SME_QOS_QOS_ON); 5249 5250 /* Inform this TSPEC IE change to FW */ 5251 opmode = wlan_get_opmode_from_vdev_id(mac->pdev, sessionId); 5252 if (opmode == QDF_STA_MODE) 5253 wlan_roam_update_cfg(mac->psoc, sessionId, 5254 REASON_CONNECT_IES_CHANGED); 5255 5256 (void)sme_qos_process_buffered_cmd(sessionId); 5257 return QDF_STATUS_SUCCESS; 5258 } 5259 5260 /* 5261 * sme_qos_aggregate_params() - Utility function to increment the TSPEC 5262 * params per AC. Typical usage while using flow aggregation or deletion of 5263 * flows 5264 * 5265 * pInput_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains the 5266 * WMM TSPEC related info with which pCurrent_Tspec_Info will be updated 5267 * pCurrent_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains 5268 * current the WMM TSPEC related info 5269 * 5270 * Return QDF_STATUS 5271 */ 5272 static QDF_STATUS sme_qos_aggregate_params( 5273 struct sme_qos_wmmtspecinfo *pInput_Tspec_Info, 5274 struct sme_qos_wmmtspecinfo *pCurrent_Tspec_Info, 5275 struct sme_qos_wmmtspecinfo *pUpdated_Tspec_Info) 5276 { 5277 struct sme_qos_wmmtspecinfo TspecInfo; 5278 5279 sme_debug("invoked"); 5280 if (!pInput_Tspec_Info) { 5281 sme_err("input is NULL, nothing to aggregate"); 5282 return QDF_STATUS_E_FAILURE; 5283 } 5284 if (!pCurrent_Tspec_Info) { 5285 sme_err("Current is NULL, can't aggregate"); 5286 return QDF_STATUS_E_FAILURE; 5287 } 5288 qdf_mem_copy(&TspecInfo, pCurrent_Tspec_Info, 5289 sizeof(struct sme_qos_wmmtspecinfo)); 5290 TspecInfo.ts_info.psb = pInput_Tspec_Info->ts_info.psb; 5291 /* APSD preference is only meaningful if service interval 5292 * was set by app 5293 */ 5294 if (pCurrent_Tspec_Info->min_service_interval && 5295 pInput_Tspec_Info->min_service_interval && 5296 (pCurrent_Tspec_Info->ts_info.direction != 5297 pInput_Tspec_Info->ts_info.direction)) { 5298 TspecInfo.min_service_interval = 5299 QDF_MIN(pCurrent_Tspec_Info->min_service_interval, 5300 pInput_Tspec_Info->min_service_interval); 5301 } else if (pInput_Tspec_Info->min_service_interval) { 5302 TspecInfo.min_service_interval = 5303 pInput_Tspec_Info->min_service_interval; 5304 } 5305 if (pCurrent_Tspec_Info->max_service_interval && 5306 pInput_Tspec_Info->max_service_interval && 5307 (pCurrent_Tspec_Info->ts_info.direction != 5308 pInput_Tspec_Info->ts_info.direction)) { 5309 TspecInfo.max_service_interval = 5310 QDF_MIN(pCurrent_Tspec_Info->max_service_interval, 5311 pInput_Tspec_Info->max_service_interval); 5312 } else { 5313 TspecInfo.max_service_interval = 5314 pInput_Tspec_Info->max_service_interval; 5315 } 5316 /* If directions don't match, it must necessarily be both uplink and 5317 * downlink 5318 */ 5319 if (pCurrent_Tspec_Info->ts_info.direction != 5320 pInput_Tspec_Info->ts_info.direction) 5321 TspecInfo.ts_info.direction = 5322 pInput_Tspec_Info->ts_info.direction; 5323 5324 /* Max MSDU size : these sizes are `maxed' */ 5325 TspecInfo.maximum_msdu_size = 5326 QDF_MAX(pCurrent_Tspec_Info->maximum_msdu_size, 5327 pInput_Tspec_Info->maximum_msdu_size); 5328 5329 /* Inactivity interval : these sizes are `maxed' */ 5330 TspecInfo.inactivity_interval = 5331 QDF_MAX(pCurrent_Tspec_Info->inactivity_interval, 5332 pInput_Tspec_Info->inactivity_interval); 5333 5334 /* Delay bounds: min of all values 5335 * Check on 0: if 0, it means initial value since delay can never be 0!! 5336 */ 5337 if (pCurrent_Tspec_Info->delay_bound) { 5338 TspecInfo.delay_bound = 5339 QDF_MIN(pCurrent_Tspec_Info->delay_bound, 5340 pInput_Tspec_Info->delay_bound); 5341 } else 5342 TspecInfo.delay_bound = pInput_Tspec_Info->delay_bound; 5343 5344 TspecInfo.max_burst_size = QDF_MAX(pCurrent_Tspec_Info->max_burst_size, 5345 pInput_Tspec_Info->max_burst_size); 5346 5347 /* Nominal MSDU size also has a fixed bit that needs to be `handled' 5348 * before aggregation This can be handled only if previous size is the 5349 * same as new or both have the fixed bit set These sizes are not added 5350 * but `maxed' 5351 */ 5352 TspecInfo.nominal_msdu_size = 5353 QDF_MAX(pCurrent_Tspec_Info->nominal_msdu_size & 5354 ~SME_QOS_16BIT_MSB, pInput_Tspec_Info->nominal_msdu_size 5355 & ~SME_QOS_16BIT_MSB); 5356 5357 if (((pCurrent_Tspec_Info->nominal_msdu_size == 0) || 5358 (pCurrent_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB)) && 5359 ((pInput_Tspec_Info->nominal_msdu_size == 0) || 5360 (pInput_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB))) 5361 TspecInfo.nominal_msdu_size |= SME_QOS_16BIT_MSB; 5362 5363 /* Data rates: Add up the rates for aggregation */ 5364 SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.peak_data_rate, 5365 pInput_Tspec_Info->peak_data_rate); 5366 SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.min_data_rate, 5367 pInput_Tspec_Info->min_data_rate); 5368 /* mean data rate = peak data rate: aggregate to be flexible on apps */ 5369 SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.mean_data_rate, 5370 pInput_Tspec_Info->mean_data_rate); 5371 5372 /* 5373 * Suspension interval : this is set to the inactivity interval since 5374 * per spec it is less than or equal to inactivity interval 5375 * This is not provided by app since we currently don't support the HCCA 5376 * mode of operation Currently set it to 0 to avoid confusion: Cisco ESE 5377 * needs ~0; spec requires inactivity interval to be > suspension 5378 * interval: this could be tricky! 5379 */ 5380 TspecInfo.suspension_interval = pInput_Tspec_Info->suspension_interval; 5381 /* Remaining parameters do not come from app as they are very WLAN 5382 * air interface specific Set meaningful values here 5383 */ 5384 TspecInfo.medium_time = 0; /* per WMM spec */ 5385 TspecInfo.min_phy_rate = SME_QOS_MIN_PHY_RATE; 5386 TspecInfo.svc_start_time = 0; /* arbitrary */ 5387 TspecInfo.surplus_bw_allowance += 5388 pInput_Tspec_Info->surplus_bw_allowance; 5389 if (TspecInfo.surplus_bw_allowance > SME_QOS_SURPLUS_BW_ALLOWANCE) 5390 TspecInfo.surplus_bw_allowance = SME_QOS_SURPLUS_BW_ALLOWANCE; 5391 5392 /* Set ack_policy to block ack even if one stream requests block 5393 * ack policy 5394 */ 5395 if ((pInput_Tspec_Info->ts_info.ack_policy == 5396 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) 5397 || (pCurrent_Tspec_Info->ts_info.ack_policy == 5398 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK)) 5399 TspecInfo.ts_info.ack_policy = 5400 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; 5401 5402 if (pInput_Tspec_Info->ts_info.burst_size_defn 5403 || pCurrent_Tspec_Info->ts_info.burst_size_defn) 5404 TspecInfo.ts_info.burst_size_defn = 1; 5405 5406 if (pUpdated_Tspec_Info) 5407 qdf_mem_copy(pUpdated_Tspec_Info, &TspecInfo, 5408 sizeof(struct sme_qos_wmmtspecinfo)); 5409 else 5410 qdf_mem_copy(pCurrent_Tspec_Info, &TspecInfo, 5411 sizeof(struct sme_qos_wmmtspecinfo)); 5412 5413 return QDF_STATUS_SUCCESS; 5414 } 5415 5416 /* 5417 * sme_qos_update_params() - Utility function to update the TSPEC 5418 * params per AC. Typical usage while deleting flows on AC which is running 5419 * multiple flows 5420 * 5421 * sessionId - Session upon which the TSPEC is being updated 5422 * ac - Enumeration of the various EDCA Access Categories. 5423 * tspec_mask - on which tspec per AC, the update is requested 5424 * 5425 * Return QDF_STATUS 5426 */ 5427 static QDF_STATUS sme_qos_update_params(uint8_t sessionId, 5428 enum qca_wlan_ac_type ac, 5429 uint8_t tspec_mask, 5430 struct sme_qos_wmmtspecinfo *pTspec_Info) 5431 { 5432 tListElem *pEntry = NULL, *pNextEntry = NULL; 5433 struct sme_qos_sessioninfo *pSession; 5434 struct sme_qos_acinfo *pACInfo; 5435 struct sme_qos_flowinfoentry *flow_info = NULL; 5436 struct sme_qos_wmmtspecinfo Tspec_Info; 5437 5438 sme_debug("invoked on session %d for AC %d TSPEC %d", 5439 sessionId, ac, tspec_mask); 5440 if (!pTspec_Info) { 5441 sme_err("output is NULL, can't aggregate"); 5442 return QDF_STATUS_E_FAILURE; 5443 } 5444 qdf_mem_zero(&Tspec_Info, sizeof(struct sme_qos_wmmtspecinfo)); 5445 pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 5446 if (!pEntry) { 5447 sme_err("Flow List empty, nothing to update"); 5448 return QDF_STATUS_E_FAILURE; 5449 } 5450 pSession = &sme_qos_cb.sessionInfo[sessionId]; 5451 pACInfo = &pSession->ac_info[ac]; 5452 /* init the TS info field */ 5453 Tspec_Info.ts_info.up = 5454 pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.up; 5455 Tspec_Info.ts_info.psb = 5456 pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.psb; 5457 Tspec_Info.ts_info.tid = 5458 pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.tid; 5459 while (pEntry) { 5460 pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); 5461 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, 5462 link); 5463 if ((sessionId == flow_info->sessionId) && 5464 (ac == flow_info->ac_type) && 5465 (tspec_mask == flow_info->tspec_mask)) { 5466 sme_debug("Flow %d matches", flow_info->QosFlowID); 5467 5468 if ((SME_QOS_REASON_RELEASE == flow_info->reason) || 5469 (SME_QOS_REASON_MODIFY == flow_info->reason)) { 5470 /* msg */ 5471 sme_debug("Skipping Flow %d as it is marked for release/modify", 5472 flow_info->QosFlowID); 5473 } else 5474 if (!QDF_IS_STATUS_SUCCESS 5475 (sme_qos_aggregate_params 5476 (&flow_info->QoSInfo, &Tspec_Info, 5477 NULL))) { 5478 /* err msg */ 5479 sme_err("sme_qos_aggregate_params() failed"); 5480 } 5481 } 5482 pEntry = pNextEntry; 5483 } 5484 /* return the aggregate */ 5485 *pTspec_Info = Tspec_Info; 5486 return QDF_STATUS_SUCCESS; 5487 } 5488 5489 /* 5490 * sme_qos_up_to_ac() - Utility function to map an UP to AC 5491 * 5492 * up - Enumeration of the various User priorities (UP). 5493 * Return an Access Category 5494 */ 5495 static enum qca_wlan_ac_type sme_qos_up_to_ac(enum sme_qos_wmmuptype up) 5496 { 5497 enum qca_wlan_ac_type ac = QCA_WLAN_AC_ALL; 5498 5499 if (up >= 0 && up < SME_QOS_WMM_UP_MAX) 5500 ac = sme_qos_up_to_ac_map[up]; 5501 5502 sme_debug("up = %d ac = %d returned", up, ac); 5503 return ac; 5504 } 5505 5506 /* 5507 * sme_qos_state_transition() - The state transition function per AC. We 5508 * save the previous state also. 5509 * 5510 * sessionId - Session upon which the state machine is running 5511 * ac - Enumeration of the various EDCA Access Categories. 5512 * new_state - The state FSM is moving to. 5513 * 5514 * Return None 5515 */ 5516 static void sme_qos_state_transition(uint8_t sessionId, 5517 enum qca_wlan_ac_type ac, 5518 enum sme_qos_states new_state) 5519 { 5520 struct sme_qos_sessioninfo *pSession; 5521 struct sme_qos_acinfo *pACInfo; 5522 5523 pSession = &sme_qos_cb.sessionInfo[sessionId]; 5524 pACInfo = &pSession->ac_info[ac]; 5525 pACInfo->prev_state = pACInfo->curr_state; 5526 pACInfo->curr_state = new_state; 5527 } 5528 5529 /** 5530 * sme_qos_find_in_flow_list() - find a flow entry from the flow list 5531 * @search_key: We can either use the flowID or the ac type to find the 5532 * entry in the flow list. 5533 * A bitmap in struct sme_qos_searchinfo tells which key to use. 5534 * Starting from LSB, 5535 * bit 0 - Flow ID 5536 * bit 1 - AC type 5537 * 5538 * Utility function to find an flow entry from the flow_list. 5539 * 5540 * Return: pointer to the list element 5541 */ 5542 static tListElem *sme_qos_find_in_flow_list(struct sme_qos_searchinfo 5543 search_key) 5544 { 5545 tListElem *list_elt = NULL, *list_next_elt = NULL; 5546 struct sme_qos_flowinfoentry *flow_info = NULL; 5547 5548 list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 5549 if (!list_elt) { 5550 sme_err("Flow List empty, can't search"); 5551 return NULL; 5552 } 5553 5554 while (list_elt) { 5555 list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, 5556 false); 5557 flow_info = GET_BASE_ADDR(list_elt, struct 5558 sme_qos_flowinfoentry, link); 5559 5560 if ((search_key.sessionId != flow_info->sessionId) && 5561 (search_key.sessionId != SME_QOS_SEARCH_SESSION_ID_ANY)) { 5562 list_elt = list_next_elt; 5563 continue; 5564 } 5565 5566 if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_1) { 5567 if (search_key.key.QosFlowID == flow_info->QosFlowID) { 5568 sme_debug("match found on flowID, ending search"); 5569 break; 5570 } 5571 } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_2) { 5572 if (search_key.key.ac_type == flow_info->ac_type) { 5573 sme_debug("match found on ac, ending search"); 5574 break; 5575 } 5576 } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_3) { 5577 if (search_key.key.reason == flow_info->reason) { 5578 sme_debug("match found on reason, ending search"); 5579 break; 5580 } 5581 } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_4) { 5582 if ((search_key.key.ac_type == flow_info->ac_type) && 5583 (search_key.direction == 5584 flow_info->QoSInfo.ts_info.direction)) { 5585 sme_debug("match found on reason, ending search"); 5586 break; 5587 } 5588 } 5589 list_elt = list_next_elt; 5590 } 5591 return list_elt; 5592 } 5593 5594 /** 5595 * sme_qos_find_all_in_flow_list() - find a flow entry in the flow list 5596 * @mac_ctx: global MAC context 5597 * @search_key: search key 5598 * @fnp: function pointer specifying the action type for the entry found 5599 * 5600 * Utility function to find an flow entry from the flow_list & act on it. 5601 * search_key - We can either use the flowID or the ac type to find the 5602 * entry in the flow list. 5603 * A bitmap in struct sme_qos_searchinfo tells which key to use. Starting from 5604 * LSB, 5605 * bit 0 - Flow ID 5606 * bit 1 - AC type 5607 * 5608 * Return: None 5609 */ 5610 static QDF_STATUS sme_qos_find_all_in_flow_list(struct mac_context *mac_ctx, 5611 struct sme_qos_searchinfo search_key, 5612 sme_QosProcessSearchEntry fnp) 5613 { 5614 tListElem *list_elt = NULL, *list_next_elt = NULL; 5615 struct sme_qos_sessioninfo *qos_session; 5616 struct sme_qos_flowinfoentry *flow_info = NULL; 5617 QDF_STATUS status = QDF_STATUS_E_FAILURE; 5618 enum qca_wlan_ac_type ac_type; 5619 5620 list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 5621 if (!list_elt) { 5622 sme_err("Flow List empty, can't search"); 5623 return QDF_STATUS_E_FAILURE; 5624 } 5625 5626 while (list_elt) { 5627 list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, 5628 false); 5629 flow_info = GET_BASE_ADDR(list_elt, struct 5630 sme_qos_flowinfoentry, link); 5631 qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 5632 if ((search_key.sessionId != flow_info->sessionId) && 5633 (search_key.sessionId != SME_QOS_SEARCH_SESSION_ID_ANY)) { 5634 list_elt = list_next_elt; 5635 continue; 5636 } 5637 5638 if ((search_key.index & SME_QOS_SEARCH_KEY_INDEX_1) && 5639 (search_key.key.QosFlowID == flow_info->QosFlowID)) { 5640 sme_debug("match found on flowID, ending search"); 5641 status = fnp(mac_ctx, list_elt); 5642 if (QDF_STATUS_E_FAILURE == status) { 5643 sme_err("Failed to process entry"); 5644 break; 5645 } 5646 } else if ((search_key.index & SME_QOS_SEARCH_KEY_INDEX_2) && 5647 (search_key.key.ac_type == flow_info->ac_type)) { 5648 sme_debug("match found on ac, ending search"); 5649 ac_type = flow_info->ac_type; 5650 flow_info->hoRenewal = 5651 qos_session->ac_info[ac_type].hoRenewal; 5652 status = fnp(mac_ctx, list_elt); 5653 if (QDF_STATUS_E_FAILURE == status) { 5654 sme_err("Failed to process entry"); 5655 break; 5656 } 5657 } 5658 list_elt = list_next_elt; 5659 } 5660 return status; 5661 } 5662 5663 /* 5664 * sme_qos_is_acm() - Utility function to check if a particular AC 5665 * mandates Admission Control. 5666 * 5667 * ac - Enumeration of the various EDCA Access Categories. 5668 * 5669 * Return true if the AC mandates Admission Control 5670 */ 5671 static bool 5672 sme_qos_is_acm(struct mac_context *mac, struct bss_description *pSirBssDesc, 5673 enum qca_wlan_ac_type ac, tDot11fBeaconIEs *pIes) 5674 { 5675 bool ret_val = false; 5676 tDot11fBeaconIEs *pIesLocal; 5677 5678 if (pIes) 5679 /* IEs were provided so use them locally */ 5680 pIesLocal = pIes; 5681 else { 5682 /* IEs were not provided so parse them ourselves */ 5683 if (!QDF_IS_STATUS_SUCCESS 5684 (csr_get_parsed_bss_description_ies 5685 (mac, pSirBssDesc, &pIesLocal))) { 5686 /* err msg */ 5687 sme_err("csr_get_parsed_bss_description_ies() failed"); 5688 return false; 5689 } 5690 5691 /* if success then pIesLocal was allocated */ 5692 } 5693 5694 if (CSR_IS_QOS_BSS(pIesLocal)) { 5695 switch (ac) { 5696 case QCA_WLAN_AC_BE: 5697 if (pIesLocal->WMMParams.acbe_acm) 5698 ret_val = true; 5699 break; 5700 case QCA_WLAN_AC_BK: 5701 if (pIesLocal->WMMParams.acbk_acm) 5702 ret_val = true; 5703 break; 5704 case QCA_WLAN_AC_VI: 5705 if (pIesLocal->WMMParams.acvi_acm) 5706 ret_val = true; 5707 break; 5708 case QCA_WLAN_AC_VO: 5709 if (pIesLocal->WMMParams.acvo_acm) 5710 ret_val = true; 5711 break; 5712 default: 5713 sme_err("unknown AC = %d", ac); 5714 break; 5715 } 5716 } /* IS_QOS_BSS */ 5717 if (!pIes) 5718 /* IEs were allocated locally so free them */ 5719 qdf_mem_free(pIesLocal); 5720 5721 return ret_val; 5722 } 5723 5724 /** 5725 * sme_qos_buffer_existing_flows() - buffer existing flows in flow_list 5726 * @mac_ctx: global MAC context 5727 * @sessionid: session ID 5728 * 5729 * Utility function to buffer the existing flows in flow_list, 5730 * so that we can renew them after handoff is done. 5731 * 5732 * Return: QDF_STATUS 5733 */ 5734 static QDF_STATUS sme_qos_buffer_existing_flows(struct mac_context *mac_ctx, 5735 uint8_t sessionid) 5736 { 5737 tListElem *list_entry = NULL, *list_nextentry = NULL; 5738 struct sme_qos_sessioninfo *qos_session; 5739 struct sme_qos_flowinfoentry *flow_info = NULL; 5740 struct sme_qos_cmdinfo cmd; 5741 struct sme_qos_setupcmdinfo *setupinfo; 5742 5743 list_entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 5744 if (!list_entry) { 5745 sme_err("Flow List empty, nothing to buffer"); 5746 return QDF_STATUS_E_FAILURE; 5747 } 5748 5749 while (list_entry) { 5750 list_nextentry = csr_ll_next(&sme_qos_cb.flow_list, list_entry, 5751 false); 5752 flow_info = GET_BASE_ADDR(list_entry, struct 5753 sme_qos_flowinfoentry, link); 5754 if (flow_info->sessionId != sessionid) { 5755 list_entry = list_nextentry; 5756 continue; 5757 } 5758 5759 if ((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) || 5760 (SME_QOS_REASON_SETUP == flow_info->reason)) { 5761 cmd.command = SME_QOS_SETUP_REQ; 5762 cmd.mac = mac_ctx; 5763 cmd.sessionId = sessionid; 5764 setupinfo = &cmd.u.setupCmdInfo; 5765 5766 setupinfo->HDDcontext = flow_info->HDDcontext; 5767 setupinfo->QoSInfo = flow_info->QoSInfo; 5768 setupinfo->QoSCallback = flow_info->QoSCallback; 5769 /* shouldn't be needed */ 5770 setupinfo->UPType = SME_QOS_WMM_UP_MAX; 5771 setupinfo->QosFlowID = flow_info->QosFlowID; 5772 if (SME_QOS_REASON_SETUP == flow_info->reason) 5773 setupinfo->hoRenewal = false; 5774 else 5775 setupinfo->hoRenewal = true; 5776 5777 if (!QDF_IS_STATUS_SUCCESS 5778 (sme_qos_buffer_cmd(&cmd, true))) 5779 sme_err("couldn't buffer the setup request for flow %d in handoff state", 5780 flow_info->QosFlowID); 5781 else 5782 sme_debug("buffered a setup request for flow %d in handoff state", 5783 flow_info->QosFlowID); 5784 } else if (SME_QOS_REASON_RELEASE == flow_info->reason) { 5785 cmd.command = SME_QOS_RELEASE_REQ; 5786 cmd.mac = mac_ctx; 5787 cmd.sessionId = sessionid; 5788 cmd.u.releaseCmdInfo.QosFlowID = flow_info->QosFlowID; 5789 if (!QDF_IS_STATUS_SUCCESS 5790 (sme_qos_buffer_cmd(&cmd, true))) 5791 sme_err("couldn't buffer the release req for flow %d in handoff state", 5792 flow_info->QosFlowID); 5793 else 5794 sme_debug("buffered a release request for flow %d in handoff state", 5795 flow_info->QosFlowID); 5796 } else if (SME_QOS_REASON_MODIFY_PENDING == 5797 flow_info->reason) { 5798 cmd.command = SME_QOS_MODIFY_REQ; 5799 cmd.mac = mac_ctx; 5800 cmd.sessionId = sessionid; 5801 cmd.u.modifyCmdInfo.QosFlowID = flow_info->QosFlowID; 5802 cmd.u.modifyCmdInfo.QoSInfo = flow_info->QoSInfo; 5803 if (!QDF_IS_STATUS_SUCCESS 5804 (sme_qos_buffer_cmd(&cmd, true))) 5805 sme_err("couldn't buffer the modify req for flow %d in handoff state", 5806 flow_info->QosFlowID); 5807 else 5808 sme_debug("buffered a modify request for flow %d in handoff state", 5809 flow_info->QosFlowID); 5810 } 5811 /* delete the entry from Flow List */ 5812 sme_debug("Deleting original entry at %pK with flowID %d", 5813 flow_info, flow_info->QosFlowID); 5814 csr_ll_remove_entry(&sme_qos_cb.flow_list, list_entry, true); 5815 qdf_mem_free(flow_info); 5816 5817 list_entry = list_nextentry; 5818 } 5819 qos_session = &sme_qos_cb.sessionInfo[sessionid]; 5820 return QDF_STATUS_SUCCESS; 5821 } 5822 5823 /* 5824 * sme_qos_delete_existing_flows() - Utility function to Delete the existing 5825 * flows in flow_list, if we lost connectivity. 5826 * 5827 * Return QDF_STATUS 5828 */ 5829 static QDF_STATUS sme_qos_delete_existing_flows(struct mac_context *mac, 5830 uint8_t sessionId) 5831 { 5832 tListElem *pEntry = NULL, *pNextEntry = NULL; 5833 struct sme_qos_flowinfoentry *flow_info = NULL; 5834 5835 pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, true); 5836 if (!pEntry) 5837 return QDF_STATUS_E_FAILURE; 5838 5839 while (pEntry) { 5840 pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, true); 5841 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, 5842 link); 5843 if (flow_info->sessionId == sessionId) { 5844 if ((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) || 5845 (SME_QOS_REASON_SETUP == flow_info->reason) || 5846 (SME_QOS_REASON_RELEASE == flow_info->reason) || 5847 (SME_QOS_REASON_MODIFY == flow_info->reason)) { 5848 flow_info->QoSCallback(MAC_HANDLE(mac), 5849 flow_info->HDDcontext, 5850 NULL, 5851 SME_QOS_STATUS_RELEASE_QOS_LOST_IND, 5852 flow_info->QosFlowID); 5853 } 5854 sme_debug("Deleting entry at %pK with flowID %d", 5855 flow_info, flow_info->QosFlowID); 5856 /* delete the entry from Flow List */ 5857 csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, 5858 true); 5859 qdf_mem_free(flow_info); 5860 } 5861 pEntry = pNextEntry; 5862 } 5863 return QDF_STATUS_SUCCESS; 5864 } 5865 5866 /** 5867 * sme_qos_buffer_cmd() - buffer a request. 5868 * @pcmd: a pointer to the cmd structure to be saved inside the buffered 5869 * cmd link list 5870 * @insert_head: flag indicate if cmd should be added to the list head. 5871 * 5872 * Utility function to buffer a request (setup/modify/release) from client 5873 * while processing another one on the same AC. 5874 * 5875 * Return: QDF_STATUS 5876 */ 5877 static QDF_STATUS sme_qos_buffer_cmd(struct sme_qos_cmdinfo *pcmd, 5878 bool insert_head) 5879 { 5880 struct sme_qos_sessioninfo *pSession; 5881 struct sme_qos_cmdinfoentry *pentry = NULL; 5882 5883 sme_debug("Invoked"); 5884 pentry = qdf_mem_malloc(sizeof(struct sme_qos_cmdinfoentry)); 5885 if (!pentry) 5886 return QDF_STATUS_E_NOMEM; 5887 5888 /* copy the entire CmdInfo */ 5889 pentry->cmdInfo = *pcmd; 5890 5891 pSession = &sme_qos_cb.sessionInfo[pcmd->sessionId]; 5892 if (insert_head) 5893 csr_ll_insert_head(&pSession->bufferedCommandList, 5894 &pentry->link, true); 5895 else 5896 csr_ll_insert_tail(&pSession->bufferedCommandList, 5897 &pentry->link, true); 5898 5899 return QDF_STATUS_SUCCESS; 5900 } 5901 5902 /** 5903 * sme_qos_process_buffered_cmd() - process qos buffered request 5904 * @session_id: Session ID 5905 * 5906 * Utility function to process a buffered request (setup/modify/release) 5907 * initially came from the client. 5908 * 5909 * Return:QDF_STATUS 5910 */ 5911 static QDF_STATUS sme_qos_process_buffered_cmd(uint8_t session_id) 5912 { 5913 struct sme_qos_sessioninfo *qos_session; 5914 struct sme_qos_cmdinfoentry *pcmd = NULL; 5915 tListElem *list_elt = NULL; 5916 enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 5917 QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; 5918 struct sme_qos_cmdinfo *qos_cmd = NULL; 5919 5920 qos_session = &sme_qos_cb.sessionInfo[session_id]; 5921 if (!csr_ll_is_list_empty(&qos_session->bufferedCommandList, false)) { 5922 list_elt = csr_ll_remove_head(&qos_session->bufferedCommandList, 5923 true); 5924 if (!list_elt) { 5925 sme_err("no more buffered commands on session %d", 5926 session_id); 5927 return QDF_STATUS_E_FAILURE; 5928 } 5929 pcmd = GET_BASE_ADDR(list_elt, struct sme_qos_cmdinfoentry, 5930 link); 5931 qos_cmd = &pcmd->cmdInfo; 5932 5933 sme_debug("Qos cmd %d", qos_cmd->command); 5934 switch (qos_cmd->command) { 5935 case SME_QOS_SETUP_REQ: 5936 hdd_status = sme_qos_internal_setup_req( 5937 qos_cmd->mac, qos_cmd->sessionId, 5938 &qos_cmd->u.setupCmdInfo.QoSInfo, 5939 qos_cmd->u.setupCmdInfo.QoSCallback, 5940 qos_cmd->u.setupCmdInfo.HDDcontext, 5941 qos_cmd->u.setupCmdInfo.UPType, 5942 qos_cmd->u.setupCmdInfo.QosFlowID, 5943 true, qos_cmd->u.setupCmdInfo.hoRenewal); 5944 if (SME_QOS_STATUS_SETUP_FAILURE_RSP == hdd_status) { 5945 sme_err("sme_qos_internal_setup_req failed on session %d", 5946 session_id); 5947 qdf_ret_status = QDF_STATUS_E_FAILURE; 5948 } 5949 break; 5950 case SME_QOS_RELEASE_REQ: 5951 hdd_status = sme_qos_internal_release_req(qos_cmd->mac, 5952 qos_cmd->sessionId, 5953 qos_cmd->u.releaseCmdInfo.QosFlowID, 5954 true); 5955 if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == hdd_status) { 5956 sme_err("sme_qos_internal_release_req failed on session %d", 5957 session_id); 5958 qdf_ret_status = QDF_STATUS_E_FAILURE; 5959 } 5960 break; 5961 case SME_QOS_MODIFY_REQ: 5962 hdd_status = sme_qos_internal_modify_req(qos_cmd->mac, 5963 &qos_cmd->u.modifyCmdInfo.QoSInfo, 5964 qos_cmd->u.modifyCmdInfo.QosFlowID, 5965 true); 5966 if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == 5967 hdd_status) { 5968 sme_err("sme_qos_internal_modify_req failed on session %d", 5969 session_id); 5970 qdf_ret_status = QDF_STATUS_E_FAILURE; 5971 } 5972 break; 5973 case SME_QOS_RESEND_REQ: 5974 hdd_status = sme_qos_re_request_add_ts(qos_cmd->mac, 5975 qos_cmd->sessionId, 5976 &qos_cmd->u.resendCmdInfo.QoSInfo, 5977 qos_cmd->u.resendCmdInfo.ac, 5978 qos_cmd->u.resendCmdInfo.tspecMask); 5979 if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == 5980 hdd_status) { 5981 sme_err("sme_qos_re_request_add_ts failed on session %d", 5982 session_id); 5983 qdf_ret_status = QDF_STATUS_E_FAILURE; 5984 } 5985 break; 5986 default: 5987 sme_err("On session %d unknown cmd = %d", 5988 session_id, qos_cmd->command); 5989 break; 5990 } 5991 /* buffered command has been processed, reclaim the memory */ 5992 qdf_mem_free(pcmd); 5993 } 5994 5995 return qdf_ret_status; 5996 } 5997 5998 /* 5999 * sme_qos_delete_buffered_requests() - Utility function to Delete the buffered 6000 * requests in the buffered_cmd_list, if we lost connectivity. 6001 * 6002 * Return QDF_STATUS 6003 */ 6004 static QDF_STATUS sme_qos_delete_buffered_requests(struct mac_context *mac, 6005 uint8_t sessionId) 6006 { 6007 struct sme_qos_sessioninfo *pSession; 6008 struct sme_qos_cmdinfoentry *pcmd = NULL; 6009 tListElem *pEntry = NULL, *pNextEntry = NULL; 6010 6011 pSession = &sme_qos_cb.sessionInfo[sessionId]; 6012 pEntry = csr_ll_peek_head(&pSession->bufferedCommandList, true); 6013 if (!pEntry) 6014 return QDF_STATUS_E_FAILURE; 6015 6016 while (pEntry) { 6017 pNextEntry = csr_ll_next(&pSession->bufferedCommandList, pEntry, 6018 true); 6019 sme_debug("deleting entry from buffered List"); 6020 /* delete the entry from Flow List */ 6021 csr_ll_remove_entry(&pSession->bufferedCommandList, pEntry, 6022 true); 6023 /* reclaim the memory */ 6024 pcmd = GET_BASE_ADDR(pEntry, struct sme_qos_cmdinfoentry, 6025 link); 6026 qdf_mem_free(pcmd); 6027 pEntry = pNextEntry; 6028 } 6029 return QDF_STATUS_SUCCESS; 6030 } 6031 6032 /** 6033 * sme_qos_save_assoc_info() - save assoc info. 6034 * @pSession: pointer to QOS session 6035 * @pAssoc_info: pointer to the assoc structure to store the BSS descriptor 6036 * of the AP, the profile that HDD sent down with the 6037 * connect request 6038 * 6039 * Utility function to save the assoc info in the CB like BSS descriptor 6040 * of the AP, the profile that HDD sent down with the connect request, 6041 * while CSR notifies for assoc/reassoc success. 6042 * 6043 * Return: QDF_STATUS 6044 */ 6045 static QDF_STATUS sme_qos_save_assoc_info(struct sme_qos_sessioninfo *pSession, 6046 sme_QosAssocInfo *pAssoc_info) 6047 { 6048 struct bss_description *bss_desc = NULL; 6049 uint32_t bssLen = 0; 6050 6051 if (!pAssoc_info) { 6052 sme_err("pAssoc_info is NULL"); 6053 return QDF_STATUS_E_FAILURE; 6054 } 6055 /* clean up the assoc info if already set */ 6056 if (pSession->assocInfo.bss_desc) { 6057 qdf_mem_free(pSession->assocInfo.bss_desc); 6058 pSession->assocInfo.bss_desc = NULL; 6059 } 6060 bssLen = pAssoc_info->bss_desc->length + 6061 sizeof(pAssoc_info->bss_desc->length); 6062 /* save the bss Descriptor */ 6063 bss_desc = qdf_mem_malloc(bssLen); 6064 if (!bss_desc) 6065 return QDF_STATUS_E_NOMEM; 6066 6067 qdf_mem_copy(bss_desc, pAssoc_info->bss_desc, bssLen); 6068 pSession->assocInfo.bss_desc = bss_desc; 6069 /* save the apsd info from assoc */ 6070 pSession->apsdMask |= pAssoc_info->uapsd_mask; 6071 6072 /* [TODO] Do we need to update the global APSD bitmap? */ 6073 return QDF_STATUS_SUCCESS; 6074 } 6075 6076 /* 6077 * sme_qos_setup_fnp() - Utility function (pointer) to notify other entries 6078 * in FLOW list on the same AC that qos params got modified 6079 * 6080 * mac - Pointer to the global MAC parameter structure. 6081 * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) 6082 * 6083 * Return QDF_STATUS 6084 */ 6085 static QDF_STATUS sme_qos_setup_fnp(struct mac_context *mac, tListElem *pEntry) 6086 { 6087 struct sme_qos_sessioninfo *pSession; 6088 struct sme_qos_acinfo *pACInfo; 6089 struct sme_qos_flowinfoentry *flow_info = NULL; 6090 enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; 6091 enum qca_wlan_ac_type ac; 6092 6093 if (!pEntry) { 6094 sme_err("Entry is NULL"); 6095 return QDF_STATUS_E_FAILURE; 6096 } 6097 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); 6098 ac = flow_info->ac_type; 6099 pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 6100 pACInfo = &pSession->ac_info[ac]; 6101 if (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) { 6102 /* notify HDD, only the other Flows running on the AC */ 6103 flow_info->QoSCallback(MAC_HANDLE(mac), 6104 flow_info->HDDcontext, 6105 &pACInfo->curr_QoSInfo[flow_info-> 6106 tspec_mask - 1], 6107 hdd_status, flow_info->QosFlowID); 6108 sme_debug("Entry with flowID = %d getting notified", 6109 flow_info->QosFlowID); 6110 } 6111 return QDF_STATUS_SUCCESS; 6112 } 6113 6114 /* 6115 * sme_qos_modification_notify_fnp() - Utility function (pointer) to notify 6116 * other entries in FLOW list on the same AC that qos params got modified 6117 * 6118 * mac - Pointer to the global MAC parameter structure. 6119 * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) 6120 * 6121 * Return QDF_STATUS 6122 */ 6123 static QDF_STATUS sme_qos_modification_notify_fnp(struct mac_context *mac, tListElem 6124 *pEntry) 6125 { 6126 struct sme_qos_sessioninfo *pSession; 6127 struct sme_qos_acinfo *pACInfo; 6128 struct sme_qos_flowinfoentry *flow_info = NULL; 6129 enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; 6130 enum qca_wlan_ac_type ac; 6131 6132 if (!pEntry) { 6133 sme_err("Entry is NULL"); 6134 return QDF_STATUS_E_FAILURE; 6135 } 6136 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); 6137 ac = flow_info->ac_type; 6138 pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 6139 pACInfo = &pSession->ac_info[ac]; 6140 if (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) { 6141 /* notify HDD, only the other Flows running on the AC */ 6142 flow_info->QoSCallback(MAC_HANDLE(mac), 6143 flow_info->HDDcontext, 6144 &pACInfo->curr_QoSInfo[flow_info-> 6145 tspec_mask - 1], 6146 hdd_status, flow_info->QosFlowID); 6147 sme_debug("Entry with flowID = %d getting notified", 6148 flow_info->QosFlowID); 6149 } 6150 return QDF_STATUS_SUCCESS; 6151 } 6152 6153 /* 6154 * sme_qos_modify_fnp() - Utility function (pointer) to delete the original 6155 * entry in FLOW list & add the modified one 6156 * 6157 * mac - Pointer to the global MAC parameter structure. 6158 * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) 6159 * 6160 * Return QDF_STATUS 6161 */ 6162 static QDF_STATUS sme_qos_modify_fnp(struct mac_context *mac, tListElem *pEntry) 6163 { 6164 struct sme_qos_flowinfoentry *flow_info = NULL; 6165 6166 if (!pEntry) { 6167 sme_err("Entry is NULL"); 6168 return QDF_STATUS_E_FAILURE; 6169 } 6170 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); 6171 6172 sme_debug("reason %d", flow_info->reason); 6173 switch (flow_info->reason) { 6174 case SME_QOS_REASON_MODIFY_PENDING: 6175 /* set the proper reason code for the new (with modified params) 6176 * entry 6177 */ 6178 flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; 6179 break; 6180 case SME_QOS_REASON_MODIFY: 6181 /* delete the original entry from Flow List */ 6182 sme_debug("Deleting original entry at %pK with flowID %d", 6183 flow_info, flow_info->QosFlowID); 6184 csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, true); 6185 /* reclaim the memory */ 6186 qdf_mem_free(flow_info); 6187 break; 6188 default: 6189 break; 6190 } 6191 return QDF_STATUS_SUCCESS; 6192 } 6193 6194 /* 6195 * sme_qos_del_ts_ind_fnp() - Utility function (pointer) to find all Flows on 6196 * the particular AC & delete them, also send HDD indication through the 6197 * callback it registered per request 6198 * 6199 * mac - Pointer to the global MAC parameter structure. 6200 * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) 6201 * 6202 * Return QDF_STATUS 6203 */ 6204 static QDF_STATUS sme_qos_del_ts_ind_fnp(struct mac_context *mac, tListElem *pEntry) 6205 { 6206 struct sme_qos_sessioninfo *pSession; 6207 struct sme_qos_acinfo *pACInfo; 6208 struct sme_qos_flowinfoentry *flow_info = NULL; 6209 enum qca_wlan_ac_type ac; 6210 QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; 6211 enum sme_qos_statustype status; 6212 6213 if (!pEntry) { 6214 sme_err("Entry is NULL"); 6215 return QDF_STATUS_E_FAILURE; 6216 } 6217 /* delete the entry from Flow List */ 6218 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); 6219 ac = flow_info->ac_type; 6220 pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 6221 pACInfo = &pSession->ac_info[ac]; 6222 pACInfo->relTrig = SME_QOS_RELEASE_BY_AP; 6223 6224 lock_status = sme_acquire_global_lock(&mac->sme); 6225 if (!QDF_IS_STATUS_SUCCESS(lock_status)) { 6226 sme_err("Unable to obtain lock"); 6227 return QDF_STATUS_E_FAILURE; 6228 } 6229 /* Call the internal function for QoS release, adding a layer of 6230 * abstraction 6231 */ 6232 status = 6233 sme_qos_internal_release_req(mac, flow_info->sessionId, 6234 flow_info->QosFlowID, false); 6235 sme_release_global_lock(&mac->sme); 6236 sme_debug("QoS Release return status on Flow %d is %d", 6237 flow_info->QosFlowID, status); 6238 6239 return QDF_STATUS_SUCCESS; 6240 } 6241 6242 /** 6243 * sme_qos_reassoc_success_ev_fnp Notification function to HDD 6244 * 6245 * @mac_ctx: Mac context 6246 * @entry: Pointer to an entry in the flow_list 6247 * 6248 * Utility function (pointer) to notify HDD 6249 * the success for the requested flow & notify all the other flows 6250 * running on the same AC that QoS params got modified 6251 * 6252 * Return: QDF_STATUS enumaration 6253 */ 6254 static QDF_STATUS 6255 sme_qos_reassoc_success_ev_fnp(struct mac_context *mac_ctx, 6256 tListElem *entry) 6257 { 6258 struct sme_qos_sessioninfo *qos_session; 6259 struct sme_qos_acinfo *ac_info; 6260 struct sme_qos_flowinfoentry *flow_info = NULL; 6261 bool delete_entry = false; 6262 enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 6263 enum qca_wlan_ac_type ac; 6264 QDF_STATUS pmc_status = QDF_STATUS_E_FAILURE; 6265 6266 if (!entry) { 6267 sme_err("Entry is NULL"); 6268 return QDF_STATUS_E_FAILURE; 6269 } 6270 flow_info = GET_BASE_ADDR(entry, struct sme_qos_flowinfoentry, link); 6271 ac = flow_info->ac_type; 6272 qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 6273 ac_info = &qos_session->ac_info[ac]; 6274 switch (flow_info->reason) { 6275 case SME_QOS_REASON_SETUP: 6276 hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND; 6277 delete_entry = false; 6278 flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; 6279 /* -Check for the case where we had to do reassoc to 6280 * reset the apsd bit for the ac - release or modify 6281 * scenario.Notify PMC as App is looking for APSD 6282 * If we already requested then we don't need to 6283 * do anything. 6284 */ 6285 if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]. 6286 ts_info.psb) { 6287 /* this is the first flow to detect we need 6288 * PMC in UAPSD mode 6289 */ 6290 pmc_status = sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), 6291 flow_info->sessionId); 6292 /* if PMC doesn't return success right away means 6293 * it is yet to put the module in BMPS state & later 6294 * to UAPSD state 6295 */ 6296 if (QDF_STATUS_E_FAILURE == pmc_status) { 6297 hdd_status = 6298 SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED; 6299 /* we need to always notify this case */ 6300 flow_info->hoRenewal = false; 6301 } 6302 } 6303 /* for any other pmc status we declare success */ 6304 break; 6305 case SME_QOS_REASON_RELEASE: 6306 ac_info->num_flows[SME_QOS_TSPEC_INDEX_0]--; 6307 fallthrough; 6308 case SME_QOS_REASON_MODIFY: 6309 delete_entry = true; 6310 break; 6311 case SME_QOS_REASON_MODIFY_PENDING: 6312 hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND; 6313 delete_entry = false; 6314 flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; 6315 if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]. 6316 ts_info.psb) { 6317 /* this is the first flow to detect we need 6318 * PMC in UAPSD mode 6319 */ 6320 pmc_status = sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), 6321 flow_info->sessionId); 6322 /* if PMC doesn't return success right away means 6323 * it is yet to put the module in BMPS state & 6324 * later to UAPSD state 6325 */ 6326 if (QDF_STATUS_E_FAILURE == pmc_status) { 6327 hdd_status = 6328 SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED; 6329 /* we need to always notify this case */ 6330 flow_info->hoRenewal = false; 6331 } 6332 } 6333 /* for any other pmc status we declare success */ 6334 break; 6335 case SME_QOS_REASON_REQ_SUCCESS: 6336 hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; 6337 fallthrough; 6338 default: 6339 delete_entry = false; 6340 break; 6341 } 6342 if (!delete_entry) { 6343 if (!flow_info->hoRenewal) { 6344 flow_info->QoSCallback(MAC_HANDLE(mac_ctx), 6345 flow_info->HDDcontext, 6346 &ac_info->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], 6347 hdd_status, 6348 flow_info->QosFlowID); 6349 } else 6350 flow_info->hoRenewal = false; 6351 } else { 6352 /* delete the entry from Flow List */ 6353 sme_debug("Deleting entry at %pK with flowID %d", 6354 flow_info, flow_info->QosFlowID); 6355 csr_ll_remove_entry(&sme_qos_cb.flow_list, entry, true); 6356 /* reclaim the memory */ 6357 qdf_mem_free(flow_info); 6358 } 6359 return QDF_STATUS_SUCCESS; 6360 } 6361 6362 /* 6363 * sme_qos_add_ts_failure_fnp() - Utility function (pointer), 6364 * if the Addts request was for for an flow setup request, delete the entry from 6365 * Flow list & notify HDD if the Addts request was for downgrading of QoS params 6366 * because of an flow release requested on the AC, delete the entry from Flow 6367 * list & notify HDD if the Addts request was for change of QoS params because 6368 * of an flow modification requested on the AC, delete the new entry from Flow 6369 * list & notify HDD 6370 * 6371 * mac - Pointer to the global MAC parameter structure. 6372 * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) 6373 * 6374 * Return QDF_STATUS 6375 */ 6376 static QDF_STATUS sme_qos_add_ts_failure_fnp(struct mac_context *mac, tListElem 6377 *pEntry) 6378 { 6379 struct sme_qos_sessioninfo *pSession; 6380 struct sme_qos_acinfo *pACInfo; 6381 struct sme_qos_flowinfoentry *flow_info = NULL; 6382 bool inform_hdd = false; 6383 enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 6384 enum qca_wlan_ac_type ac; 6385 6386 if (!pEntry) { 6387 sme_err("Entry is NULL"); 6388 return QDF_STATUS_E_FAILURE; 6389 } 6390 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); 6391 ac = flow_info->ac_type; 6392 pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 6393 pACInfo = &pSession->ac_info[ac]; 6394 switch (flow_info->reason) { 6395 case SME_QOS_REASON_SETUP: 6396 hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 6397 pACInfo->num_flows[pACInfo->tspec_pending - 1]--; 6398 inform_hdd = true; 6399 break; 6400 case SME_QOS_REASON_RELEASE: 6401 hdd_status = SME_QOS_STATUS_RELEASE_FAILURE_RSP; 6402 pACInfo->num_flows[pACInfo->tspec_pending - 1]--; 6403 inform_hdd = true; 6404 break; 6405 case SME_QOS_REASON_MODIFY_PENDING: 6406 hdd_status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 6407 inform_hdd = true; 6408 break; 6409 case SME_QOS_REASON_MODIFY: 6410 flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; 6411 fallthrough; 6412 case SME_QOS_REASON_REQ_SUCCESS: 6413 fallthrough; 6414 default: 6415 inform_hdd = false; 6416 break; 6417 } 6418 if (inform_hdd) { 6419 /* notify HDD, only the requested Flow, other Flows running on 6420 * the AC stay intact 6421 */ 6422 if (!flow_info->hoRenewal) { 6423 flow_info->QoSCallback(MAC_HANDLE(mac), 6424 flow_info->HDDcontext, 6425 &pACInfo->curr_QoSInfo[pACInfo-> 6426 tspec_pending 6427 - 1], 6428 hdd_status, 6429 flow_info->QosFlowID); 6430 } else { 6431 flow_info->QoSCallback(MAC_HANDLE(mac), 6432 flow_info->HDDcontext, 6433 &pACInfo->curr_QoSInfo[pACInfo-> 6434 tspec_pending 6435 - 1], 6436 SME_QOS_STATUS_RELEASE_QOS_LOST_IND, 6437 flow_info->QosFlowID); 6438 } 6439 /* delete the entry from Flow List */ 6440 sme_debug("Deleting entry at %pK with flowID %d", 6441 flow_info, flow_info->QosFlowID); 6442 csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, true); 6443 /* reclaim the memory */ 6444 qdf_mem_free(flow_info); 6445 } 6446 return QDF_STATUS_SUCCESS; 6447 } 6448 6449 /** 6450 * sme_qos_add_ts_success_fnp() - Utility function (pointer) to notify HDD 6451 * 6452 * @mac_ctx: Mac context 6453 * @entry: Pointer to an entry in the flow_list(i.e. tListElem structure). 6454 * 6455 * Description : Utility function (pointer), 6456 * If the Addts request was for for an flow setup request, notify 6457 * HDD for success for the flow & notify all the other flows running 6458 * on the same AC that QoS params got modified 6459 * if the Addts request was for downgrading of QoS params 6460 * because of an flow release requested on the AC, delete 6461 * the entry from Flow list & notify HDD if the Addts request 6462 * was for change of QoS params because of an flow modification 6463 * requested on the AC, delete the old entry from Flow list & notify 6464 * HDD for success for the flow & notify all the other flows running 6465 * on the same AC that QoS params got modified 6466 * 6467 * Return: Status 6468 */ 6469 6470 static QDF_STATUS sme_qos_add_ts_success_fnp(struct mac_context *mac_ctx, 6471 tListElem *entry) 6472 { 6473 struct sme_qos_sessioninfo *qos_session; 6474 struct sme_qos_acinfo *ac_info; 6475 struct sme_qos_flowinfoentry *flow_info = NULL; 6476 bool inform_hdd = false; 6477 bool delete_entry = false; 6478 enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; 6479 enum qca_wlan_ac_type ac; 6480 QDF_STATUS pmc_status = QDF_STATUS_E_FAILURE; 6481 tCsrRoamModifyProfileFields profile_fields; 6482 uint8_t psb; 6483 uint8_t tspec_index; 6484 6485 if (!entry) { 6486 sme_err("Entry is NULL"); 6487 return QDF_STATUS_E_FAILURE; 6488 } 6489 flow_info = GET_BASE_ADDR(entry, struct sme_qos_flowinfoentry, link); 6490 ac = flow_info->ac_type; 6491 qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 6492 ac_info = &qos_session->ac_info[ac]; 6493 tspec_index = ac_info->tspec_pending - 1; 6494 if (flow_info->tspec_mask != ac_info->tspec_pending) { 6495 sme_debug(" No need to notify the HDD, the ADDTS success is not for index = %d of the AC = %d", 6496 flow_info->tspec_mask, ac); 6497 return QDF_STATUS_SUCCESS; 6498 } 6499 switch (flow_info->reason) { 6500 case SME_QOS_REASON_SETUP: 6501 hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND; 6502 flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; 6503 delete_entry = false; 6504 inform_hdd = true; 6505 /* check if App is looking for APSD 6506 * notify PMC as App is looking for APSD. If we already 6507 * requested then we don't need to do anything 6508 */ 6509 if (ac_info->requested_QoSInfo[tspec_index].ts_info.psb) { 6510 /* this is the first flow to detect we need 6511 * PMC in UAPSD mode 6512 */ 6513 pmc_status = sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), 6514 flow_info->sessionId); 6515 /* if PMC doesn't return success right away means 6516 * it is yet to put the module in BMPS state & later 6517 * to UAPSD state 6518 */ 6519 if (QDF_STATUS_E_FAILURE == pmc_status) { 6520 hdd_status = 6521 SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED; 6522 /* we need to always notify this case */ 6523 flow_info->hoRenewal = false; 6524 } 6525 } 6526 break; 6527 case SME_QOS_REASON_RELEASE: 6528 ac_info->num_flows[tspec_index]--; 6529 hdd_status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP; 6530 inform_hdd = true; 6531 delete_entry = true; 6532 break; 6533 case SME_QOS_REASON_MODIFY: 6534 delete_entry = true; 6535 inform_hdd = false; 6536 break; 6537 case SME_QOS_REASON_MODIFY_PENDING: 6538 hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND; 6539 delete_entry = false; 6540 flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; 6541 inform_hdd = true; 6542 psb = ac_info->requested_QoSInfo[tspec_index].ts_info.psb; 6543 /* notify PMC if App is looking for APSD 6544 */ 6545 if (psb) { 6546 /* this is the first flow to detect 6547 * we need PMC in UAPSD mode 6548 */ 6549 pmc_status = sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), 6550 flow_info->sessionId); 6551 /* if PMC doesn't return success right 6552 * away means it is yet to put 6553 * the module in BMPS state & later to UAPSD state 6554 */ 6555 if (QDF_STATUS_E_FAILURE == pmc_status) { 6556 hdd_status = 6557 SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED; 6558 /* we need to always notify this case */ 6559 flow_info->hoRenewal = false; 6560 } 6561 } else if (!psb && 6562 ((ac_info->num_flows[flow_info->tspec_mask - 1] == 1) 6563 && (SME_QOS_TSPEC_MASK_BIT_1_2_SET != 6564 ac_info->tspec_mask_status))) { 6565 /* this is the only TSPEC active on this AC */ 6566 /* so indicate that we no longer require APSD */ 6567 qos_session->apsdMask &= 6568 ~(1 << (QCA_WLAN_AC_VO - ac)); 6569 /* Also update modifyProfileFields.uapsd_mask 6570 * in CSR for consistency 6571 */ 6572 csr_get_modify_profile_fields(mac_ctx, 6573 flow_info->sessionId, 6574 &profile_fields); 6575 profile_fields.uapsd_mask = 6576 qos_session->apsdMask; 6577 csr_set_modify_profile_fields(mac_ctx, 6578 flow_info->sessionId, 6579 &profile_fields); 6580 if (!qos_session->apsdMask) 6581 sme_ps_uapsd_disable(MAC_HANDLE(mac_ctx), 6582 flow_info->sessionId); 6583 } 6584 break; 6585 case SME_QOS_REASON_REQ_SUCCESS: 6586 hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; 6587 inform_hdd = true; 6588 fallthrough; 6589 default: 6590 delete_entry = false; 6591 break; 6592 } 6593 if (inform_hdd) { 6594 if (!flow_info->hoRenewal) { 6595 flow_info->QoSCallback(MAC_HANDLE(mac_ctx), 6596 flow_info->HDDcontext, 6597 &ac_info->curr_QoSInfo[tspec_index], 6598 hdd_status, 6599 flow_info->QosFlowID); 6600 } else 6601 flow_info->hoRenewal = false; 6602 } 6603 if (delete_entry) { 6604 sme_debug("Deleting entry at %pK with flowID %d", 6605 flow_info, flow_info->QosFlowID); 6606 /* delete the entry from Flow List */ 6607 csr_ll_remove_entry(&sme_qos_cb.flow_list, entry, true); 6608 /* reclaim the memory */ 6609 qdf_mem_free(flow_info); 6610 } 6611 return QDF_STATUS_SUCCESS; 6612 } 6613 6614 /* 6615 * sme_qos_is_rsp_pending() - Utility function to check if we are waiting 6616 * for an AddTS or reassoc response on some AC other than the given AC 6617 * 6618 * sessionId - Session we are interted in 6619 * ac - Enumeration of the various EDCA Access Categories. 6620 * 6621 * Return bool 6622 * true - Response is pending on an AC 6623 */ 6624 static bool sme_qos_is_rsp_pending(uint8_t sessionId, enum qca_wlan_ac_type ac) 6625 { 6626 struct sme_qos_sessioninfo *pSession; 6627 struct sme_qos_acinfo *pACInfo; 6628 enum qca_wlan_ac_type acIndex; 6629 bool status = false; 6630 6631 pSession = &sme_qos_cb.sessionInfo[sessionId]; 6632 for (acIndex = QCA_WLAN_AC_BE; acIndex < QCA_WLAN_AC_ALL; 6633 acIndex++) { 6634 if (acIndex == ac) 6635 continue; 6636 pACInfo = &pSession->ac_info[acIndex]; 6637 if ((pACInfo->tspec_pending) || (pACInfo->reassoc_pending)) { 6638 status = true; 6639 break; 6640 } 6641 } 6642 return status; 6643 } 6644 6645 /* 6646 * sme_qos_update_hand_off() - Function which can be called to update 6647 * Hand-off state of SME QoS Session 6648 * 6649 * sessionId - session id 6650 * updateHandOff - value True/False to update the handoff flag 6651 */ 6652 void sme_qos_update_hand_off(uint8_t sessionId, bool updateHandOff) 6653 { 6654 struct sme_qos_sessioninfo *pSession; 6655 6656 pSession = &sme_qos_cb.sessionInfo[sessionId]; 6657 if (pSession->handoffRequested != updateHandOff) 6658 sme_debug("handoffRequested %d updateHandOff %d", 6659 pSession->handoffRequested, updateHandOff); 6660 6661 pSession->handoffRequested = updateHandOff; 6662 6663 } 6664 6665 /* 6666 * sme_qos_is_uapsd_active() - Function which can be called to determine 6667 * if any sessions require PMC to be in U-APSD mode. 6668 * Return bool 6669 * 6670 * Returns true if at least one session required PMC to be in U-APSD mode 6671 * Returns false if no sessions require PMC to be in U-APSD mode 6672 */ 6673 static bool sme_qos_is_uapsd_active(void) 6674 { 6675 struct sme_qos_sessioninfo *pSession; 6676 uint8_t sessionId; 6677 6678 for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; ++sessionId) { 6679 pSession = &sme_qos_cb.sessionInfo[sessionId]; 6680 if ((pSession->sessionActive) && (pSession->apsdMask)) 6681 return true; 6682 } 6683 /* no active sessions have U-APSD active */ 6684 return false; 6685 } 6686 6687 QDF_STATUS sme_offload_qos_process_out_of_uapsd_mode(struct mac_context *mac, 6688 uint32_t sessionId) 6689 { 6690 struct sme_qos_sessioninfo *pSession; 6691 tListElem *pEntry = NULL, *pNextEntry = NULL; 6692 struct sme_qos_flowinfoentry *flow_info = NULL; 6693 6694 pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 6695 if (!pEntry) { 6696 sme_debug("Flow List empty, can't search"); 6697 return QDF_STATUS_E_FAILURE; 6698 } 6699 while (pEntry) { 6700 pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); 6701 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, 6702 link); 6703 pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 6704 /* only notify the flows which already successfully setup 6705 * UAPSD 6706 */ 6707 if ((sessionId == flow_info->sessionId) && 6708 (flow_info->QoSInfo.max_service_interval || 6709 flow_info->QoSInfo.min_service_interval) && 6710 (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)) { 6711 flow_info->QoSCallback(MAC_HANDLE(mac), 6712 flow_info->HDDcontext, 6713 &pSession->ac_info[flow_info-> 6714 ac_type].curr_QoSInfo 6715 [flow_info->tspec_mask - 1], 6716 SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND, 6717 flow_info->QosFlowID); 6718 } 6719 pEntry = pNextEntry; 6720 } 6721 return QDF_STATUS_SUCCESS; 6722 } 6723 6724 QDF_STATUS sme_offload_qos_process_into_uapsd_mode(struct mac_context *mac, 6725 uint32_t sessionId) 6726 { 6727 struct sme_qos_sessioninfo *pSession; 6728 tListElem *pEntry = NULL, *pNextEntry = NULL; 6729 struct sme_qos_flowinfoentry *flow_info = NULL; 6730 6731 pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); 6732 if (!pEntry) { 6733 sme_err("Flow List empty, can't search"); 6734 return QDF_STATUS_E_FAILURE; 6735 } 6736 while (pEntry) { 6737 pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); 6738 flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, 6739 link); 6740 pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; 6741 /* only notify the flows which already successfully setup 6742 * UAPSD 6743 */ 6744 if ((sessionId == flow_info->sessionId) && 6745 (flow_info->QoSInfo.max_service_interval || 6746 flow_info->QoSInfo.min_service_interval) && 6747 (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)) { 6748 flow_info->QoSCallback(MAC_HANDLE(mac), 6749 flow_info->HDDcontext, 6750 &pSession->ac_info[flow_info-> 6751 ac_type].curr_QoSInfo 6752 [flow_info->tspec_mask - 1], 6753 SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND, 6754 flow_info->QosFlowID); 6755 } 6756 pEntry = pNextEntry; 6757 } 6758 return QDF_STATUS_SUCCESS; 6759 } 6760 6761 void sme_qos_cleanup_ctrl_blk_for_handoff(struct mac_context *mac, 6762 uint8_t sessionId) 6763 { 6764 struct sme_qos_sessioninfo *pSession; 6765 struct sme_qos_acinfo *pACInfo; 6766 enum qca_wlan_ac_type ac; 6767 6768 pSession = &sme_qos_cb.sessionInfo[sessionId]; 6769 sme_debug("invoked on session %d", sessionId); 6770 6771 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 6772 pACInfo = &pSession->ac_info[ac]; 6773 qdf_mem_zero(pACInfo->curr_QoSInfo, 6774 sizeof(struct sme_qos_wmmtspecinfo) * 6775 SME_QOS_TSPEC_INDEX_MAX); 6776 qdf_mem_zero(pACInfo->requested_QoSInfo, 6777 sizeof(struct sme_qos_wmmtspecinfo) * 6778 SME_QOS_TSPEC_INDEX_MAX); 6779 pACInfo->num_flows[0] = 0; 6780 pACInfo->num_flows[1] = 0; 6781 pACInfo->reassoc_pending = false; 6782 pACInfo->tspec_mask_status = 0; 6783 pACInfo->tspec_pending = false; 6784 pACInfo->hoRenewal = false; 6785 pACInfo->prev_state = SME_QOS_LINK_UP; 6786 } 6787 } 6788 6789 /** 6790 * sme_qos_is_ts_info_ack_policy_valid() - check if ACK policy is allowed. 6791 * @mac_handle: The handle returned by mac_open. 6792 * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the 6793 * WMM TSPEC related info, provided by HDD 6794 * @sessionId: sessionId returned by sme_open_session. 6795 * 6796 * The SME QoS API exposed to HDD to check if TS info ack policy field can be 6797 * set to "HT-immediate block acknowledgment" 6798 * 6799 * Return: true - Current Association is HT association and so TS info ack 6800 * policy can be set to "HT-immediate block acknowledgment" 6801 */ 6802 bool sme_qos_is_ts_info_ack_policy_valid(mac_handle_t mac_handle, 6803 struct sme_qos_wmmtspecinfo *pQoSInfo, 6804 uint8_t sessionId) 6805 { 6806 tDot11fBeaconIEs *pIes = NULL; 6807 struct sme_qos_sessioninfo *pSession; 6808 QDF_STATUS hstatus; 6809 struct mac_context *mac = MAC_CONTEXT(mac_handle); 6810 6811 if (!CSR_IS_SESSION_VALID(mac, sessionId)) { 6812 sme_err("Session Id %d is invalid", sessionId); 6813 return false; 6814 } 6815 6816 pSession = &sme_qos_cb.sessionInfo[sessionId]; 6817 6818 if (!pSession->sessionActive) { 6819 sme_err("Session %d is inactive", sessionId); 6820 return false; 6821 } 6822 6823 if (!pSession->assocInfo.bss_desc) { 6824 sme_err("Session %d has an Invalid BSS Descriptor", sessionId); 6825 return false; 6826 } 6827 6828 hstatus = csr_get_parsed_bss_description_ies(mac, 6829 pSession->assocInfo.bss_desc, 6830 &pIes); 6831 if (!QDF_IS_STATUS_SUCCESS(hstatus)) { 6832 sme_err("On session %d unable to parse BSS IEs", sessionId); 6833 return false; 6834 } 6835 6836 /* success means pIes was allocated */ 6837 6838 if (!pIes->HTCaps.present && 6839 pQoSInfo->ts_info.ack_policy == 6840 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) { 6841 sme_err("On session %d HT Caps aren't present but application set ack policy to HT ", 6842 sessionId); 6843 6844 qdf_mem_free(pIes); 6845 return false; 6846 } 6847 6848 qdf_mem_free(pIes); 6849 return true; 6850 } 6851 6852 static bool sme_qos_validate_requested_params(struct mac_context *mac, 6853 struct sme_qos_wmmtspecinfo *qos_info, 6854 uint8_t session_id) 6855 { 6856 if (SME_QOS_WMM_TS_DIR_RESV == qos_info->ts_info.direction) 6857 return false; 6858 if (!sme_qos_is_ts_info_ack_policy_valid(MAC_HANDLE(mac), 6859 qos_info, session_id)) 6860 return false; 6861 6862 return true; 6863 } 6864 6865 static QDF_STATUS qos_issue_command(struct mac_context *mac, uint8_t vdev_id, 6866 eSmeCommandType cmdType, 6867 struct sme_qos_wmmtspecinfo *pQoSInfo, 6868 enum qca_wlan_ac_type ac, uint8_t tspec_mask) 6869 { 6870 QDF_STATUS status = QDF_STATUS_E_RESOURCES; 6871 tSmeCmd *pCommand = NULL; 6872 6873 do { 6874 pCommand = csr_get_command_buffer(mac); 6875 if (!pCommand) { 6876 sme_err("fail to get command buffer for command %d", 6877 cmdType); 6878 break; 6879 } 6880 pCommand->command = cmdType; 6881 pCommand->vdev_id = vdev_id; 6882 switch (cmdType) { 6883 case eSmeCommandAddTs: 6884 if (pQoSInfo) { 6885 status = QDF_STATUS_SUCCESS; 6886 pCommand->u.qosCmd.tspecInfo = *pQoSInfo; 6887 pCommand->u.qosCmd.ac = ac; 6888 } else { 6889 sme_err("NULL pointer passed"); 6890 status = QDF_STATUS_E_INVAL; 6891 } 6892 break; 6893 case eSmeCommandDelTs: 6894 status = QDF_STATUS_SUCCESS; 6895 pCommand->u.qosCmd.ac = ac; 6896 pCommand->u.qosCmd.tspec_mask = tspec_mask; 6897 break; 6898 default: 6899 sme_err("invalid command type %d", cmdType); 6900 status = QDF_STATUS_E_INVAL; 6901 break; 6902 } 6903 } while (0); 6904 if (QDF_IS_STATUS_SUCCESS(status) && pCommand) 6905 csr_queue_sme_command(mac, pCommand, false); 6906 else if (pCommand) 6907 qos_release_command(mac, pCommand); 6908 6909 return status; 6910 } 6911 6912 bool qos_process_command(struct mac_context *mac, tSmeCmd *pCommand) 6913 { 6914 QDF_STATUS status = QDF_STATUS_SUCCESS; 6915 bool fRemoveCmd = true; 6916 6917 do { 6918 switch (pCommand->command) { 6919 case eSmeCommandAddTs: 6920 status = 6921 sme_qos_add_ts_req(mac, (uint8_t) 6922 pCommand->vdev_id, 6923 &pCommand->u.qosCmd.tspecInfo, 6924 pCommand->u.qosCmd.ac); 6925 if (QDF_IS_STATUS_SUCCESS(status)) 6926 fRemoveCmd = false; 6927 break; 6928 case eSmeCommandDelTs: 6929 status = 6930 sme_qos_del_ts_req(mac, (uint8_t) 6931 pCommand->vdev_id, 6932 pCommand->u.qosCmd.ac, 6933 pCommand->u.qosCmd.tspec_mask); 6934 if (QDF_IS_STATUS_SUCCESS(status)) 6935 fRemoveCmd = false; 6936 break; 6937 default: 6938 sme_err("invalid command type %d", pCommand->command); 6939 break; 6940 } /* switch */ 6941 } while (0); 6942 return fRemoveCmd; 6943 } 6944 6945 /** 6946 * sme_qos_re_request_add_ts - Re-send AddTS for the combined QoS request 6947 * 6948 * @mac_ctx Pointer to mac context 6949 * @session_id SME session id 6950 * @qos_info - Tspec information 6951 * @ac - Access category 6952 * @tspec_mask - Tspec Mask 6953 * 6954 * This function is called to re-send AddTS for the combined QoS request 6955 * 6956 * Return: status 6957 */ 6958 static 6959 enum sme_qos_statustype sme_qos_re_request_add_ts(struct mac_context *mac_ctx, 6960 uint8_t session_id, struct sme_qos_wmmtspecinfo *qos_info, 6961 enum qca_wlan_ac_type ac, uint8_t tspec_mask) 6962 { 6963 struct sme_qos_sessioninfo *session; 6964 struct sme_qos_acinfo *ac_info; 6965 enum sme_qos_statustype status = 6966 SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 6967 struct sme_qos_cmdinfo cmd; 6968 6969 sme_debug(" Invoked on session %d for AC %d TSPEC %d", session_id, ac, 6970 tspec_mask); 6971 session = &sme_qos_cb.sessionInfo[session_id]; 6972 ac_info = &session->ac_info[ac]; 6973 /* 6974 * call PMC's request for power function 6975 * AND another check is added considering the flowing scenario 6976 * Addts request is pending on one AC, while APSD requested on 6977 * another which needs a reassoc. Will buffer a request if Addts 6978 * is pending on any AC, which will safeguard the above scenario, 6979 * 2& also won't confuse PE with back to back Addts or Addts 6980 * followed by Reassoc. 6981 */ 6982 if (sme_qos_is_rsp_pending(session_id, ac)) { 6983 sme_err("On session %d buffering the AddTS request for AC %d in state %d as Addts is pending on other AC or waiting for full power", 6984 session_id, ac, ac_info->curr_state); 6985 /* buffer cmd */ 6986 cmd.command = SME_QOS_RESEND_REQ; 6987 cmd.mac = mac_ctx; 6988 cmd.sessionId = session_id; 6989 cmd.u.resendCmdInfo.ac = ac; 6990 cmd.u.resendCmdInfo.tspecMask = tspec_mask; 6991 cmd.u.resendCmdInfo.QoSInfo = *qos_info; 6992 if (!QDF_IS_STATUS_SUCCESS(sme_qos_buffer_cmd(&cmd, false))) { 6993 sme_err("On session %d unable to buffer the AddTS request for AC %d TSPEC %d in state %d", 6994 session_id, ac, tspec_mask, 6995 ac_info->curr_state); 6996 return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 6997 } 6998 return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; 6999 } 7000 7001 /* get into the stat m/c to see if the request can be granted */ 7002 switch (ac_info->curr_state) { 7003 case SME_QOS_QOS_ON: 7004 { 7005 /* if ACM, send out a new ADDTS */ 7006 ac_info->hoRenewal = true; 7007 status = sme_qos_setup(mac_ctx, session_id, qos_info, ac); 7008 sme_debug("sme_qos_setup returned in SME_QOS_QOS_ON state sme_qos_setup AC %d with status =%d", 7009 ac, status); 7010 if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { 7011 status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; 7012 ac_info->tspec_pending = tspec_mask; 7013 } else if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == 7014 status) || 7015 (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == 7016 status) || 7017 (SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING == 7018 status)) { 7019 sme_err("UAPSD is setup already status = %d ", status); 7020 } else { 7021 sme_err("sme_qos_setup return status = %d ", status); 7022 } 7023 } 7024 break; 7025 case SME_QOS_HANDOFF: 7026 case SME_QOS_REQUESTED: 7027 sme_err("Re-Add request in state = %d buffer the request", 7028 ac_info->curr_state); 7029 cmd.command = SME_QOS_RESEND_REQ; 7030 cmd.mac = mac_ctx; 7031 cmd.sessionId = session_id; 7032 cmd.u.resendCmdInfo.ac = ac; 7033 cmd.u.resendCmdInfo.tspecMask = tspec_mask; 7034 cmd.u.resendCmdInfo.QoSInfo = *qos_info; 7035 if (!QDF_IS_STATUS_SUCCESS(sme_qos_buffer_cmd(&cmd, false))) { 7036 sme_err(" couldn't buf the read request state = %d", 7037 ac_info->curr_state); 7038 return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; 7039 } 7040 status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; 7041 break; 7042 case SME_QOS_CLOSED: 7043 case SME_QOS_INIT: 7044 case SME_QOS_LINK_UP: 7045 default: 7046 /* print error msg, */ 7047 sme_err("Re-Add request in unexpected state = %d", 7048 ac_info->curr_state); 7049 break; 7050 } 7051 if ((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == 7052 status) || 7053 (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == 7054 status)) 7055 (void)sme_qos_process_buffered_cmd(session_id); 7056 7057 return status; 7058 } 7059 7060 static void sme_qos_init_a_cs(struct mac_context *mac, uint8_t sessionId) 7061 { 7062 struct sme_qos_sessioninfo *pSession; 7063 enum qca_wlan_ac_type ac; 7064 7065 pSession = &sme_qos_cb.sessionInfo[sessionId]; 7066 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 7067 qdf_mem_zero(&pSession->ac_info[ac], 7068 sizeof(struct sme_qos_acinfo)); 7069 sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); 7070 } 7071 } 7072 7073 static QDF_STATUS sme_qos_request_reassoc(struct mac_context *mac, 7074 uint8_t sessionId, 7075 tCsrRoamModifyProfileFields * 7076 pModFields, bool fForce) 7077 { 7078 struct sme_qos_sessioninfo *pSession; 7079 struct sme_qos_acinfo *pACInfo; 7080 QDF_STATUS status; 7081 struct qdf_mac_addr bssid; 7082 qdf_freq_t ch_freq; 7083 7084 sme_debug("Invoked on session %d with UAPSD mask 0x%X", 7085 sessionId, pModFields->uapsd_mask); 7086 7087 if (!CSR_IS_SESSION_VALID(mac, sessionId)) { 7088 sme_err("Invalid session for sessionId: %d", sessionId); 7089 return QDF_STATUS_E_FAILURE; 7090 } 7091 7092 pSession = &sme_qos_cb.sessionInfo[sessionId]; 7093 wlan_mlme_get_bssid_vdev_id(mac->pdev, sessionId, &bssid); 7094 ch_freq = wlan_get_operation_chan_freq_vdev_id(mac->pdev, sessionId); 7095 status = wlan_cm_roam_invoke(mac->pdev, sessionId, &bssid, ch_freq, 7096 CM_ROAMING_HOST); 7097 7098 if (QDF_IS_STATUS_SUCCESS(status)) { 7099 /* Update the state to Handoff so subsequent requests are 7100 * queued until this one is finished 7101 */ 7102 enum qca_wlan_ac_type ac; 7103 7104 for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { 7105 pACInfo = &pSession->ac_info[ac]; 7106 sme_debug("AC[%d] is in state [%d]", 7107 ac, pACInfo->curr_state); 7108 /* If it is already in HANDOFF state, don't do 7109 * anything since we MUST preserve the previous state 7110 * and sme_qos_state_transition will change the previous 7111 * state 7112 */ 7113 if (SME_QOS_HANDOFF != pACInfo->curr_state) 7114 sme_qos_state_transition(sessionId, ac, 7115 SME_QOS_HANDOFF); 7116 } 7117 } 7118 return status; 7119 } 7120 7121 static uint32_t sme_qos_assign_flow_id(void) 7122 { 7123 uint32_t flowId; 7124 7125 flowId = sme_qos_cb.nextFlowId; 7126 if (SME_QOS_MAX_FLOW_ID == flowId) { 7127 /* The Flow ID wrapped. This is obviously not a real life 7128 * scenario but handle it to keep the software test folks happy 7129 */ 7130 sme_debug("Software Test made the flow counter wrap, QoS may no longer be functional"); 7131 sme_qos_cb.nextFlowId = SME_QOS_MIN_FLOW_ID; 7132 } else 7133 sme_qos_cb.nextFlowId++; 7134 7135 return flowId; 7136 } 7137 7138 static uint8_t sme_qos_assign_dialog_token(void) 7139 { 7140 uint8_t token; 7141 7142 token = sme_qos_cb.nextDialogToken; 7143 if (SME_QOS_MAX_DIALOG_TOKEN == token) 7144 /* wrap is ok */ 7145 sme_qos_cb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN; 7146 else 7147 sme_qos_cb.nextDialogToken++; 7148 7149 sme_debug("token %d", token); 7150 return token; 7151 } 7152 #endif /* WLAN_MDM_CODE_REDUCTION_OPT */ 7153