xref: /wlan-driver/qcacld-3.0/core/sme/src/qos/sme_qos.c (revision 5113495b16420b49004c444715d2daae2066e7dc) !
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