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
sme_qos_allocate_control_block_buffer(void)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
sme_qos_free_control_block_buffer(void)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
sme_qos_allocate_control_block_buffer(void)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
sme_qos_free_control_block_buffer(void)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 */
sme_qos_open(struct mac_context * mac)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 */
sme_qos_close(struct mac_context * mac)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 */
sme_qos_setup_req(mac_handle_t mac_handle,uint32_t sessionId,struct sme_qos_wmmtspecinfo * pQoSInfo,sme_QosCallback QoSCallback,void * HDDcontext,enum sme_qos_wmmuptype UPType,uint32_t * pQosFlowID)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 */
sme_qos_modify_req(mac_handle_t mac_handle,struct sme_qos_wmmtspecinfo * pQoSInfo,uint32_t QosFlowID)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 */
sme_qos_release_req(mac_handle_t mac_handle,uint8_t session_id,uint32_t QosFlowID)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
qos_release_command(struct mac_context * mac,tSmeCmd * pCommand)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 */
sme_qos_msg_processor(struct mac_context * mac_ctx,uint16_t msg_type,void * msg)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
sme_qos_process_disconnect_roam_ind(struct mac_context * mac,uint8_t vdev_id)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 */
sme_qos_csr_event_ind(struct mac_context * mac,uint8_t sessionId,sme_qos_csr_event_indType ind,void * pEvent_info)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 */
sme_qos_get_acm_mask(struct mac_context * mac,struct bss_description * pSirBssDesc,tDot11fBeaconIEs * pIes)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 */
sme_qos_internal_setup_req(struct mac_context * mac,uint8_t sessionId,struct sme_qos_wmmtspecinfo * pQoSInfo,sme_QosCallback QoSCallback,void * HDDcontext,enum sme_qos_wmmuptype UPType,uint32_t QosFlowID,bool buffered_cmd,bool hoRenewal)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 */
sme_qos_internal_modify_req(struct mac_context * mac,struct sme_qos_wmmtspecinfo * pQoSInfo,uint32_t QosFlowID,bool buffered_cmd)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 */
sme_qos_internal_release_req(struct mac_context * mac,uint8_t sessionId,uint32_t QosFlowID,bool buffered_cmd)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 */
sme_qos_setup(struct mac_context * mac,uint8_t sessionId,struct sme_qos_wmmtspecinfo * pTspec_Info,enum qca_wlan_ac_type ac)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 */
sme_qos_process_set_key_success_ind(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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
sme_qos_ese_save_tspec_response(struct mac_context * mac,uint8_t sessionId,tDot11fIEWMMTSPEC * pTspec,uint8_t ac,uint8_t tspecIndex)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
sme_qos_ese_process_reassoc_tspec_rsp(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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 */
sme_qos_copy_tspec_info(struct mac_context * mac,struct sme_qos_wmmtspecinfo * pTspec_Info,struct mac_tspec_ie * pTspec)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 */
sme_qos_ese_retrieve_tspec_info(struct mac_context * mac_ctx,uint8_t session_id,tTspecInfo * tspec_info)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
sme_qos_create_tspec_ricie(struct mac_context * mac,struct sme_qos_wmmtspecinfo * tspec_info,uint8_t * ric_buffer,uint32_t * ric_length,uint8_t * ric_identifier)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 */
sme_qos_process_ft_reassoc_req_ev(uint8_t sessionId)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 */
sme_qos_fill_aggr_info(int ac_id,int ts_id,enum sme_qos_wmm_dir_type direction,tSirAggrQosReq * msg,struct sme_qos_sessioninfo * session)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 */
sme_qos_ft_aggr_qos_req(struct mac_context * mac_ctx,uint8_t session_id)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
sme_qos_process_ftric_response(struct mac_context * mac,uint8_t sessionId,tDot11fIERICDataDesc * pRicDataDesc,uint8_t ac,uint8_t tspecIndex)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 */
sme_qos_process_aggr_qos_rsp(struct mac_context * mac_ctx,void * msgbuf)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 */
sme_qos_find_matching_tspec(struct mac_context * mac_ctx,uint8_t sessionid,uint8_t ac,struct sme_qos_acinfo * ac_info,tDot11fIERICDataDesc * ric_data_desc,uint32_t * ric_rsplen)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 */
sme_qos_find_matching_tspec_lfr3(struct mac_context * mac_ctx,uint8_t sessionid,uint8_t ac,struct sme_qos_sessioninfo * qos_session,tDot11fIERICDataDesc * ric_data_desc,uint32_t ric_rsplen)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
sme_qos_process_ft_reassoc_rsp_ev(struct mac_context * mac_ctx,uint8_t sessionid,void * event_info)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
sme_send_mscs_action_frame(uint8_t vdev_id)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 */
sme_qos_add_ts_req(struct mac_context * mac,uint8_t sessionId,struct sme_qos_wmmtspecinfo * pTspec_Info,enum qca_wlan_ac_type ac)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 */
sme_qos_del_ts_req(struct mac_context * mac,uint8_t sessionId,enum qca_wlan_ac_type ac,uint8_t tspec_mask)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 */
sme_qos_process_add_ts_rsp(struct mac_context * mac,void * msg_buf)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
sme_qos_process_del_ts_rsp(struct mac_context * mac,void * msg_buf)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 */
sme_qos_process_del_ts_ind(struct mac_context * mac,void * msg_buf)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 */
sme_qos_process_assoc_complete_ev(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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 */
sme_qos_process_reassoc_req_ev(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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
sme_qos_handle_handoff_state(struct mac_context * mac_ctx,struct sme_qos_sessioninfo * qos_session,struct sme_qos_acinfo * ac_info,enum qca_wlan_ac_type ac,uint8_t sessionid)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 */
sme_qos_process_reassoc_success_ev(struct mac_context * mac_ctx,uint8_t sessionid,void * event_info)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 */
sme_qos_process_reassoc_failure_ev(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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
sme_qos_ft_handoff_required(struct mac_context * mac,uint8_t session_id)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
sme_qos_ft_handoff_required(struct mac_context * mac,uint8_t session_id)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
sme_qos_ft_handoff_required(struct mac_context * mac,uint8_t session_id)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
sme_qos_legacy_handoff_required(struct mac_context * mac,uint8_t session_id)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
sme_qos_legacy_handoff_required(struct mac_context * mac,uint8_t session_id)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 */
sme_qos_process_handoff_assoc_req_ev(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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 */
sme_qos_process_handoff_success_ev(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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 */
sme_qos_process_disconnect_ev(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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 */
sme_qos_process_join_req_ev(struct mac_context * mac,uint8_t sessionId,void * pEvent_info)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 */
sme_qos_process_preauth_success_ind(struct mac_context * mac_ctx,uint8_t sessionid,void * event_info)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
sme_qos_process_preauth_success_ind(struct mac_context * mac_ctx,uint8_t sessionid,void * event_info)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 */
sme_qos_process_add_ts_failure_rsp(struct mac_context * mac,uint8_t sessionId,tSirAddtsRspInfo * pRsp)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 */
sme_qos_update_tspec_mask(uint8_t sessionid,struct sme_qos_searchinfo search_key,uint8_t new_tspec_mask)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 */
sme_qos_process_add_ts_success_rsp(struct mac_context * mac,uint8_t sessionId,tSirAddtsRspInfo * pRsp)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 */
sme_qos_aggregate_params(struct sme_qos_wmmtspecinfo * pInput_Tspec_Info,struct sme_qos_wmmtspecinfo * pCurrent_Tspec_Info,struct sme_qos_wmmtspecinfo * pUpdated_Tspec_Info)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 */
sme_qos_update_params(uint8_t sessionId,enum qca_wlan_ac_type ac,uint8_t tspec_mask,struct sme_qos_wmmtspecinfo * pTspec_Info)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 */
sme_qos_up_to_ac(enum sme_qos_wmmuptype up)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 */
sme_qos_state_transition(uint8_t sessionId,enum qca_wlan_ac_type ac,enum sme_qos_states new_state)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 */
sme_qos_find_in_flow_list(struct sme_qos_searchinfo search_key)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 */
sme_qos_find_all_in_flow_list(struct mac_context * mac_ctx,struct sme_qos_searchinfo search_key,sme_QosProcessSearchEntry fnp)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
sme_qos_is_acm(struct mac_context * mac,struct bss_description * pSirBssDesc,enum qca_wlan_ac_type ac,tDot11fBeaconIEs * pIes)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 */
sme_qos_buffer_existing_flows(struct mac_context * mac_ctx,uint8_t sessionid)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 */
sme_qos_delete_existing_flows(struct mac_context * mac,uint8_t sessionId)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 */
sme_qos_buffer_cmd(struct sme_qos_cmdinfo * pcmd,bool insert_head)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 */
sme_qos_process_buffered_cmd(uint8_t session_id)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 */
sme_qos_delete_buffered_requests(struct mac_context * mac,uint8_t sessionId)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 */
sme_qos_save_assoc_info(struct sme_qos_sessioninfo * pSession,sme_QosAssocInfo * pAssoc_info)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 */
sme_qos_setup_fnp(struct mac_context * mac,tListElem * pEntry)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 */
sme_qos_modification_notify_fnp(struct mac_context * mac,tListElem * pEntry)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 */
sme_qos_modify_fnp(struct mac_context * mac,tListElem * pEntry)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 */
sme_qos_del_ts_ind_fnp(struct mac_context * mac,tListElem * pEntry)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
sme_qos_reassoc_success_ev_fnp(struct mac_context * mac_ctx,tListElem * entry)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 */
sme_qos_add_ts_failure_fnp(struct mac_context * mac,tListElem * pEntry)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
sme_qos_add_ts_success_fnp(struct mac_context * mac_ctx,tListElem * entry)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 */
sme_qos_is_rsp_pending(uint8_t sessionId,enum qca_wlan_ac_type ac)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 */
sme_qos_update_hand_off(uint8_t sessionId,bool updateHandOff)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 */
sme_qos_is_uapsd_active(void)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
sme_offload_qos_process_out_of_uapsd_mode(struct mac_context * mac,uint32_t sessionId)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
sme_offload_qos_process_into_uapsd_mode(struct mac_context * mac,uint32_t sessionId)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
sme_qos_cleanup_ctrl_blk_for_handoff(struct mac_context * mac,uint8_t sessionId)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 */
sme_qos_is_ts_info_ack_policy_valid(mac_handle_t mac_handle,struct sme_qos_wmmtspecinfo * pQoSInfo,uint8_t sessionId)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
sme_qos_validate_requested_params(struct mac_context * mac,struct sme_qos_wmmtspecinfo * qos_info,uint8_t session_id)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
qos_issue_command(struct mac_context * mac,uint8_t vdev_id,eSmeCommandType cmdType,struct sme_qos_wmmtspecinfo * pQoSInfo,enum qca_wlan_ac_type ac,uint8_t tspec_mask)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
qos_process_command(struct mac_context * mac,tSmeCmd * pCommand)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
sme_qos_re_request_add_ts(struct mac_context * mac_ctx,uint8_t session_id,struct sme_qos_wmmtspecinfo * qos_info,enum qca_wlan_ac_type ac,uint8_t tspec_mask)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
sme_qos_init_a_cs(struct mac_context * mac,uint8_t sessionId)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
sme_qos_request_reassoc(struct mac_context * mac,uint8_t sessionId,tCsrRoamModifyProfileFields * pModFields,bool fForce)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
sme_qos_assign_flow_id(void)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
sme_qos_assign_dialog_token(void)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