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