blob: 3cbff0221040e36de14af1017e31f3f7713372a0 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302 * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
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 * DOC: HDD WMM
30 *
31 * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation)
32 * houses all the logic for WMM in HDD.
33 *
34 * On the control path, it has the logic to setup QoS, modify QoS and delete
35 * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an
36 * explicit application invoked and an internal HDD invoked. The implicit QoS
37 * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but
38 * which DO mark their traffic for priortization. It also has logic to start,
39 * update and stop the U-APSD trigger frame generation. It also has logic to
40 * read WMM related config parameters from the registry.
41 *
42 * On the data path, it has the logic to figure out the WMM AC of an egress
43 * packet and when to signal TL to serve a particular AC queue. It also has the
44 * logic to retrieve a packet based on WMM priority in response to a fetch from
45 * TL.
46 *
47 * The remaining functions are utility functions for information hiding.
48 */
49
50/* Include files */
51#include <linux/netdevice.h>
52#include <linux/skbuff.h>
53#include <linux/etherdevice.h>
54#include <linux/if_vlan.h>
55#include <linux/ip.h>
56#include <linux/semaphore.h>
Govind Singhb7ab5772015-10-08 16:38:37 +053057#include <linux/ipv6.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080058#include <wlan_hdd_tx_rx.h>
59#include <wlan_hdd_wmm.h>
60#include <wlan_hdd_ether.h>
61#include <wlan_hdd_hostapd.h>
62#include <wlan_hdd_softap_tx_rx.h>
63#include <cds_sched.h>
64
65/* change logging behavior based upon debug flag */
66#ifdef HDD_WMM_DEBUG
67#define WMM_TRACE_LEVEL_FATAL CDF_TRACE_LEVEL_FATAL
68#define WMM_TRACE_LEVEL_ERROR CDF_TRACE_LEVEL_FATAL
69#define WMM_TRACE_LEVEL_WARN CDF_TRACE_LEVEL_FATAL
70#define WMM_TRACE_LEVEL_INFO CDF_TRACE_LEVEL_FATAL
71#define WMM_TRACE_LEVEL_INFO_HIGH CDF_TRACE_LEVEL_FATAL
72#define WMM_TRACE_LEVEL_INFO_LOW CDF_TRACE_LEVEL_FATAL
73#else
74#define WMM_TRACE_LEVEL_FATAL CDF_TRACE_LEVEL_FATAL
75#define WMM_TRACE_LEVEL_ERROR CDF_TRACE_LEVEL_ERROR
76#define WMM_TRACE_LEVEL_WARN CDF_TRACE_LEVEL_WARN
77#define WMM_TRACE_LEVEL_INFO CDF_TRACE_LEVEL_INFO
78#define WMM_TRACE_LEVEL_INFO_HIGH CDF_TRACE_LEVEL_INFO_HIGH
79#define WMM_TRACE_LEVEL_INFO_LOW CDF_TRACE_LEVEL_INFO_LOW
80#endif
81
82#define WLAN_HDD_MAX_DSCP 0x3f
83
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080084#define HDD_WMM_UP_TO_AC_MAP_SIZE 8
85
86const uint8_t hdd_wmm_up_to_ac_map[] = {
87 SME_AC_BE,
88 SME_AC_BK,
89 SME_AC_BK,
90 SME_AC_BE,
91 SME_AC_VI,
92 SME_AC_VI,
93 SME_AC_VO,
94 SME_AC_VO
95};
96
97/**
98 * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to
99 * operate on different traffic.
100 */
101#ifdef QCA_LL_TX_FLOW_CONTROL_V2
102enum hdd_wmm_linuxac {
103 HDD_LINUX_AC_VO = 0,
104 HDD_LINUX_AC_VI = 1,
105 HDD_LINUX_AC_BE = 2,
106 HDD_LINUX_AC_BK = 3,
107 HDD_LINUX_AC_HI_PRIO = 4,
108};
109
110void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter)
111{
112 /* Enable HI_PRIO queue */
113 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VO);
114 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VI);
115 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BE);
116 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BK);
117 netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO);
118
119}
120#else
121enum hdd_wmm_linuxac {
122 HDD_LINUX_AC_VO = 0,
123 HDD_LINUX_AC_VI = 1,
124 HDD_LINUX_AC_BE = 2,
125 HDD_LINUX_AC_BK = 3
126};
127
128void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter)
129{
130 return;
131}
132#endif
133
134/* Linux based UP -> AC Mapping */
135const uint8_t hdd_linux_up_to_ac_map[HDD_WMM_UP_TO_AC_MAP_SIZE] = {
136 HDD_LINUX_AC_BE,
137 HDD_LINUX_AC_BK,
138 HDD_LINUX_AC_BK,
139 HDD_LINUX_AC_BE,
140 HDD_LINUX_AC_VI,
141 HDD_LINUX_AC_VI,
142 HDD_LINUX_AC_VO,
143 HDD_LINUX_AC_VO
144};
145
146#ifndef WLAN_MDM_CODE_REDUCTION_OPT
147/**
148 * hdd_wmm_enable_tl_uapsd() - function which decides whether and
149 * how to update UAPSD parameters in TL
150 *
151 * @pQosContext: [in] the pointer the QoS instance control block
152 *
153 * Return: None
154 */
155static void hdd_wmm_enable_tl_uapsd(hdd_wmm_qos_context_t *pQosContext)
156{
157 hdd_adapter_t *pAdapter = pQosContext->pAdapter;
158 sme_ac_enum_type acType = pQosContext->acType;
159 hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
160 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530161 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800162 uint32_t service_interval;
163 uint32_t suspension_interval;
164 sme_QosWmmDirType direction;
165 bool psb;
166
167 /* The TSPEC must be valid */
168 if (pAc->wmmAcTspecValid == false) {
169 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
170 "%s: Invoked with invalid TSPEC", __func__);
171 return;
172 }
173 /* determine the service interval */
174 if (pAc->wmmAcTspecInfo.min_service_interval) {
175 service_interval = pAc->wmmAcTspecInfo.min_service_interval;
176 } else if (pAc->wmmAcTspecInfo.max_service_interval) {
177 service_interval = pAc->wmmAcTspecInfo.max_service_interval;
178 } else {
179 /* no service interval is present in the TSPEC */
180 /* this is OK, there just won't be U-APSD */
181 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
182 "%s: No service interval supplied", __func__);
183 service_interval = 0;
184 }
185
186 /* determine the suspension interval & direction */
187 suspension_interval = pAc->wmmAcTspecInfo.suspension_interval;
188 direction = pAc->wmmAcTspecInfo.ts_info.direction;
189 psb = pAc->wmmAcTspecInfo.ts_info.psb;
190
191 /* if we have previously enabled U-APSD, have any params changed? */
192 if ((pAc->wmmAcUapsdInfoValid) &&
193 (pAc->wmmAcUapsdServiceInterval == service_interval) &&
194 (pAc->wmmAcUapsdSuspensionInterval == suspension_interval) &&
195 (pAc->wmmAcUapsdDirection == direction) &&
196 (pAc->wmmAcIsUapsdEnabled == psb)) {
197 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
198 "%s: No change in U-APSD parameters", __func__);
199 return;
200 }
201 /* everything is in place to notify TL */
202 status =
203 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
204 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->
205 conn_info.staId[0], acType,
206 pAc->wmmAcTspecInfo.ts_info.tid,
207 pAc->wmmAcTspecInfo.ts_info.up,
208 service_interval, suspension_interval,
209 direction, psb, pAdapter->sessionId,
210 pHddCtx->config->DelayedTriggerFrmInt);
211
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530212 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800213 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
214 "%s: Failed to enable U-APSD for AC=%d",
215 __func__, acType);
216 return;
217 }
218 /* stash away the parameters that were used */
219 pAc->wmmAcUapsdInfoValid = true;
220 pAc->wmmAcUapsdServiceInterval = service_interval;
221 pAc->wmmAcUapsdSuspensionInterval = suspension_interval;
222 pAc->wmmAcUapsdDirection = direction;
223 pAc->wmmAcIsUapsdEnabled = psb;
224
225 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
226 "%s: Enabled UAPSD in TL srv_int=%d "
227 "susp_int=%d dir=%d AC=%d",
228 __func__,
229 service_interval, suspension_interval, direction, acType);
230
231}
232
233/**
234 * hdd_wmm_disable_tl_uapsd() - function which decides whether
235 * to disable UAPSD parameters in TL
236 *
237 * @pQosContext: [in] the pointer the QoS instance control block
238 *
239 * Return: None
240 */
241static void hdd_wmm_disable_tl_uapsd(hdd_wmm_qos_context_t *pQosContext)
242{
243 hdd_adapter_t *pAdapter = pQosContext->pAdapter;
244 sme_ac_enum_type acType = pQosContext->acType;
245 hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530246 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800247
248 /* have we previously enabled UAPSD? */
249 if (pAc->wmmAcUapsdInfoValid == true) {
Sreelakshmi Konamkie1ce5622015-11-23 15:04:05 +0530250 status =
251 sme_disable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
252 pcds_context,
253 (WLAN_HDD_GET_STATION_CTX_PTR
254 (pAdapter))->conn_info.staId[0],
255 acType, pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530257 if (!QDF_IS_STATUS_SUCCESS(status)) {
Sreelakshmi Konamkie1ce5622015-11-23 15:04:05 +0530258 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
259 "%s: Failed to disable U-APSD for AC=%d",
260 __func__, acType);
261 } else {
262 /* TL no longer has valid UAPSD info */
263 pAc->wmmAcUapsdInfoValid = false;
264 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
265 "%s: Disabled UAPSD in TL for AC=%d",
266 __func__, acType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800267 }
268 }
269}
270
271#endif
272
273/**
274 * hdd_wmm_free_context() - function which frees a QoS context
275 *
276 * @pQosContext: [in] the pointer the QoS instance control block
277 *
278 * Return: None
279 */
280static void hdd_wmm_free_context(hdd_wmm_qos_context_t *pQosContext)
281{
282 hdd_adapter_t *pAdapter;
283
284 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
285 "%s: Entered, context %p", __func__, pQosContext);
286
287 if (unlikely((NULL == pQosContext) ||
288 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
289 /* must have been freed in another thread */
290 return;
291 }
292 /* get pointer to the adapter context */
293 pAdapter = pQosContext->pAdapter;
294
295 /* take the wmmLock since we're manipulating the context list */
296 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
297
298 /* make sure nobody thinks this is a valid context */
299 pQosContext->magic = 0;
300
301 /* unlink the context */
302 list_del(&pQosContext->node);
303
304 /* done manipulating the list */
305 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
306
307 /* reclaim memory */
308 kfree(pQosContext);
309
310}
311
312#ifndef WLAN_MDM_CODE_REDUCTION_OPT
313/**
314 * hdd_wmm_notify_app() - function which notifies an application
315 * of changes in state of it flow
316 *
317 * @pQosContext: [in] the pointer the QoS instance control block
318 *
319 * Return: None
320 */
321#define MAX_NOTIFY_LEN 50
322static void hdd_wmm_notify_app(hdd_wmm_qos_context_t *pQosContext)
323{
324 hdd_adapter_t *pAdapter;
325 union iwreq_data wrqu;
326 char buf[MAX_NOTIFY_LEN + 1];
327
328 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
329 "%s: Entered, context %p", __func__, pQosContext);
330
331 if (unlikely((NULL == pQosContext) ||
332 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
333 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
334 "%s: Invalid QoS Context", __func__);
335 return;
336 }
337
338 /* create the event */
339 memset(&wrqu, 0, sizeof(wrqu));
340 memset(buf, 0, sizeof(buf));
341
342 snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]",
343 (unsigned int)pQosContext->handle,
344 (unsigned int)pQosContext->lastStatus);
345
346 wrqu.data.pointer = buf;
347 wrqu.data.length = strlen(buf);
348
349 /* get pointer to the adapter */
350 pAdapter = pQosContext->pAdapter;
351
352 /* send the event */
353 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
354 "%s: Sending [%s]", __func__, buf);
355 wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf);
356}
357
358#ifdef FEATURE_WLAN_ESE
359/**
360 * hdd_wmm_inactivity_timer_cb() - inactivity timer callback function
361 *
362 * @user_data: opaque user data registered with the timer. In the
363 * case of this timer, the associated wmm QoS context is registered.
364 *
365 * This timer handler function is called for every inactivity interval
366 * per AC. This function gets the current transmitted packets on the
367 * given AC, and checks if there was any TX activity from the previous
368 * interval. If there was no traffic then it would delete the TS that
369 * was negotiated on that AC.
370 *
371 * Return: None
372 */
373static void hdd_wmm_inactivity_timer_cb(void *user_data)
374{
375 hdd_wmm_qos_context_t *pQosContext = user_data;
376 hdd_adapter_t *pAdapter;
377 hdd_wmm_ac_status_t *pAc;
378 hdd_wlan_wmm_status_e status;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530379 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800380 uint32_t currentTrafficCnt = 0;
381 sme_ac_enum_type acType = pQosContext->acType;
382
383 pAdapter = pQosContext->pAdapter;
384 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
385
386 /* Get the Tx stats for this AC. */
387 currentTrafficCnt =
388 pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext->
389 acType];
390
391 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN,
392 FL(
393 "WMM inactivity Timer for AC=%d, currentCnt=%d, prevCnt=%d"
394 ),
395 acType, (int)currentTrafficCnt, (int)pAc->wmmPrevTrafficCnt);
396 if (pAc->wmmPrevTrafficCnt == currentTrafficCnt) {
397 /* there is no traffic activity, delete the TSPEC for this AC */
398 status = hdd_wmm_delts(pAdapter, pQosContext->handle);
399 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_WARN,
400 FL(
401 "Deleted TS on AC %d, due to inactivity with status = %d!!!"
402 ),
403 acType, status);
404 } else {
405 pAc->wmmPrevTrafficCnt = currentTrafficCnt;
406 if (pAc->wmmInactivityTimer.state == CDF_TIMER_STATE_STOPPED) {
407 /* Restart the timer */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530408 qdf_status =
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800409 cdf_mc_timer_start(&pAc->wmmInactivityTimer,
410 pAc->wmmInactivityTime);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530411 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800412 CDF_TRACE(CDF_MODULE_ID_HDD,
413 CDF_TRACE_LEVEL_ERROR,
414 FL(
415 "Restarting inactivity timer failed on AC %d"
416 ),
417 acType);
418 }
419 } else {
420 CDF_ASSERT(cdf_mc_timer_get_current_state
421 (&pAc->wmmInactivityTimer) ==
422 CDF_TIMER_STATE_STOPPED);
423 }
424 }
425
426 return;
427}
428
429/**
430 * hdd_wmm_enable_inactivity_timer() -
431 * function to enable the traffic inactivity timer for the given AC
432 *
433 * @pQosContext: [in] pointer to pQosContext
434 * @inactivityTime: [in] value of the inactivity interval in millisecs
435 *
436 * When a QoS-Tspec is successfully setup, if the inactivity interval
437 * time specified in the AddTS parameters is non-zero, this function
438 * is invoked to start a traffic inactivity timer for the given AC.
439 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530440 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800441 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530442static QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800443hdd_wmm_enable_inactivity_timer(hdd_wmm_qos_context_t *pQosContext,
444 uint32_t inactivityTime)
445{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530446 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800447 hdd_adapter_t *pAdapter = pQosContext->pAdapter;
448 sme_ac_enum_type acType = pQosContext->acType;
449 hdd_wmm_ac_status_t *pAc;
450
451 pAdapter = pQosContext->pAdapter;
452 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
453
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530454 qdf_status = cdf_mc_timer_init(&pAc->wmmInactivityTimer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800455 CDF_TIMER_TYPE_SW,
456 hdd_wmm_inactivity_timer_cb,
457 pQosContext);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530458 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800459 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
460 FL("Initializing inactivity timer failed on AC %d"),
461 acType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530462 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800463 }
464 /* Start the inactivity timer */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530465 qdf_status = cdf_mc_timer_start(&pAc->wmmInactivityTimer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800466 inactivityTime);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530467 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800468 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
469 FL("Starting inactivity timer failed on AC %d"),
470 acType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530471 qdf_status = cdf_mc_timer_destroy(&pAc->wmmInactivityTimer);
472 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800473 hdd_err("Failed to destroy inactivity timer");
474 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530475 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 }
477 pAc->wmmInactivityTime = inactivityTime;
478 /* Initialize the current tx traffic count on this AC */
479 pAc->wmmPrevTrafficCnt =
480 pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext->
481 acType];
482 pQosContext->is_inactivity_timer_running = true;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530483 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800484}
485
486/**
487 * hdd_wmm_disable_inactivity_timer() -
488 * function to disable the traffic inactivity timer for the given AC.
489 *
490 * @pQosContext: [in] pointer to pQosContext
491 *
492 * This function is invoked to disable the traffic inactivity timer
493 * for the given AC. This is normally done when the TS is deleted.
494 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530495 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800496 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530497static QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800498hdd_wmm_disable_inactivity_timer(hdd_wmm_qos_context_t *pQosContext)
499{
500 hdd_adapter_t *pAdapter = pQosContext->pAdapter;
501 sme_ac_enum_type acType = pQosContext->acType;
502 hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530503 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800504
505 /* Clear the timer and the counter */
506 pAc->wmmInactivityTime = 0;
507 pAc->wmmPrevTrafficCnt = 0;
508
509 if (pQosContext->is_inactivity_timer_running == true) {
510 pQosContext->is_inactivity_timer_running = false;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530511 qdf_status = cdf_mc_timer_stop(&pAc->wmmInactivityTimer);
512 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800513 hdd_err("Failed to stop inactivity timer");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530514 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800515 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530516 qdf_status = cdf_mc_timer_destroy(&pAc->wmmInactivityTimer);
517 if (!QDF_IS_STATUS_SUCCESS(qdf_status))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800518 hdd_err("Failed to destroy inactivity timer:Timer started");
519 }
520
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530521 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800522}
523#endif /* FEATURE_WLAN_ESE */
524
525/**
526 * hdd_wmm_sme_callback() - callback for QoS notifications
527 *
528 * @hHal: [in] the HAL handle
529 * @hddCtx : [in] the HDD specified handle
530 * @pCurrentQosInfo : [in] the TSPEC params
531 * @smeStatus : [in] the QoS related SME status
532 * @qosFlowId: [in] the unique identifier of the flow
533 *
534 * This callback is registered by HDD with SME for receiving QoS
535 * notifications. Even though this function has a static scope it
536 * gets called externally through some function pointer magic (so
537 * there is a need for rigorous parameter checking).
538 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530539 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800540 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530541static QDF_STATUS hdd_wmm_sme_callback(tHalHandle hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542 void *hddCtx,
543 sme_QosWmmTspecInfo *pCurrentQosInfo,
544 sme_QosStatusType smeStatus,
545 uint32_t qosFlowId)
546{
547 hdd_wmm_qos_context_t *pQosContext = hddCtx;
548 hdd_adapter_t *pAdapter;
549 sme_ac_enum_type acType;
550 hdd_wmm_ac_status_t *pAc;
551
552 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
553 "%s: Entered, context %p", __func__, pQosContext);
554
555 if (unlikely((NULL == pQosContext) ||
556 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
557 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
558 "%s: Invalid QoS Context", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530559 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800560 }
561
562 pAdapter = pQosContext->pAdapter;
563 acType = pQosContext->acType;
564 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
565
566 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
567 "%s: status %d flowid %d info %p",
568 __func__, smeStatus, qosFlowId, pCurrentQosInfo);
569
570 switch (smeStatus) {
571
572 case SME_QOS_STATUS_SETUP_SUCCESS_IND:
573 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
574 "%s: Setup is complete", __func__);
575
576 /* there will always be a TSPEC returned with this
577 * status, even if a TSPEC is not exchanged OTA
578 */
579 if (pCurrentQosInfo) {
580 pAc->wmmAcTspecValid = true;
581 memcpy(&pAc->wmmAcTspecInfo,
582 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
583 }
584 pAc->wmmAcAccessAllowed = true;
585 pAc->wmmAcAccessGranted = true;
586 pAc->wmmAcAccessPending = false;
587 pAc->wmmAcAccessFailed = false;
588
589 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
590
591 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
592 "%s: Explicit Qos, notifying user space",
593 __func__);
594
595 /* this was triggered by an application */
596 pQosContext->lastStatus =
597 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
598 hdd_wmm_notify_app(pQosContext);
599 }
600
601#ifdef FEATURE_WLAN_ESE
602 /* Check if the inactivity interval is specified */
603 if (pCurrentQosInfo && pCurrentQosInfo->inactivity_interval) {
604 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
605 "%s: Inactivity timer value = %d for AC=%d",
606 __func__,
607 pCurrentQosInfo->inactivity_interval, acType);
608 hdd_wmm_enable_inactivity_timer(pQosContext,
609 pCurrentQosInfo->
610 inactivity_interval);
611 }
612#endif /* FEATURE_WLAN_ESE */
613
614 /* notify TL to enable trigger frames if necessary */
615 hdd_wmm_enable_tl_uapsd(pQosContext);
616
617 break;
618
619 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
620 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
621 "%s: Setup is complete (U-APSD set previously)",
622 __func__);
623
624 pAc->wmmAcAccessAllowed = true;
625 pAc->wmmAcAccessGranted = true;
626 pAc->wmmAcAccessPending = false;
627
628 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
629
630 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
631 "%s: Explicit Qos, notifying user space",
632 __func__);
633
634 /* this was triggered by an application */
635 pQosContext->lastStatus =
636 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
637 hdd_wmm_notify_app(pQosContext);
638 }
639
640 break;
641
642 case SME_QOS_STATUS_SETUP_FAILURE_RSP:
643 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
644 "%s: Setup failed", __func__);
645 /* QoS setup failed */
646
647 pAc->wmmAcAccessPending = false;
648 pAc->wmmAcAccessFailed = true;
649 pAc->wmmAcAccessAllowed = false;
650 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
651
652 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
653 "%s: Explicit Qos, notifying user space",
654 __func__);
655
656 /* this was triggered by an application */
657 pQosContext->lastStatus =
658 HDD_WLAN_WMM_STATUS_SETUP_FAILED;
659
660 hdd_wmm_notify_app(pQosContext);
661 }
662
663 /* Setting up QoS Failed, QoS context can be released.
664 * SME is releasing this flow information and if HDD
665 * doesn't release this context, next time if
666 * application uses the same handle to set-up QoS, HDD
667 * (as it has QoS context for this handle) will issue
668 * Modify QoS request to SME but SME will reject as now
669 * it has no information for this flow.
670 */
671 hdd_wmm_free_context(pQosContext);
672 break;
673
674 case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
675 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
676 "%s: Setup Invalid Params, notify TL", __func__);
677 /* QoS setup failed */
678 pAc->wmmAcAccessAllowed = false;
679
680 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
681
682 /* we note the failure, but we also mark
683 * access as allowed so that the packets will
684 * flow. Note that the MAC will "do the right
685 * thing"
686 */
687 pAc->wmmAcAccessPending = false;
688 pAc->wmmAcAccessFailed = true;
689 pAc->wmmAcAccessAllowed = true;
690
691 } else {
692 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
693 "%s: Explicit Qos, notifying user space",
694 __func__);
695
696 /* this was triggered by an application */
697 pQosContext->lastStatus =
698 HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
699 hdd_wmm_notify_app(pQosContext);
700 }
701 break;
702
703 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
704 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
705 "%s: Setup failed, not a QoS AP", __func__);
706 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
707 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
708 "%s: Explicit Qos, notifying user space",
709 __func__);
710
711 /* this was triggered by an application */
712 pQosContext->lastStatus =
713 HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
714 hdd_wmm_notify_app(pQosContext);
715 }
716 break;
717
718 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
719 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
720 "%s: Setup pending", __func__);
721 /* not a callback status -- ignore if we get it */
722 break;
723
724 case SME_QOS_STATUS_SETUP_MODIFIED_IND:
725 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
726 "%s: Setup modified", __func__);
727 if (pCurrentQosInfo) {
728 /* update the TSPEC */
729 pAc->wmmAcTspecValid = true;
730 memcpy(&pAc->wmmAcTspecInfo,
731 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
732
733 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
734 CDF_TRACE(CDF_MODULE_ID_HDD,
735 WMM_TRACE_LEVEL_INFO,
736 "%s: Explicit Qos, notifying user space",
737 __func__);
738
739 /* this was triggered by an application */
740 pQosContext->lastStatus =
741 HDD_WLAN_WMM_STATUS_MODIFIED;
742 hdd_wmm_notify_app(pQosContext);
743 }
744 /* need to tell TL to update its UAPSD handling */
745 hdd_wmm_enable_tl_uapsd(pQosContext);
746 }
747 break;
748
749 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
750 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
751
752 /* this was triggered by implicit QoS so we
753 * know packets are pending
754 */
755 pAc->wmmAcAccessPending = false;
756 pAc->wmmAcAccessGranted = true;
757 pAc->wmmAcAccessAllowed = true;
758
759 } else {
760 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
761 "%s: Explicit Qos, notifying user space",
762 __func__);
763
764 /* this was triggered by an application */
765 pQosContext->lastStatus =
766 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
767 hdd_wmm_notify_app(pQosContext);
768 }
769 break;
770
771 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
772 /* nothing to do for now */
773 break;
774
775 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED:
776 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
777 "%s: Setup successful but U-APSD failed", __func__);
778
779 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
780
781 /* QoS setup was successful but setting U=APSD
782 * failed. Since the OTA part of the request
783 * was successful, we don't mark this as a
784 * failure. the packets will flow. Note that
785 * the MAC will "do the right thing" */
786 pAc->wmmAcAccessGranted = true;
787 pAc->wmmAcAccessAllowed = true;
788 pAc->wmmAcAccessFailed = false;
789 pAc->wmmAcAccessPending = false;
790
791 } else {
792 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
793 "%s: Explicit Qos, notifying user space",
794 __func__);
795
796 /* this was triggered by an application */
797 pQosContext->lastStatus =
798 HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED;
799 hdd_wmm_notify_app(pQosContext);
800 }
801
802 /* Since U-APSD portion failed disabled trigger frame
803 * generation
804 */
805 hdd_wmm_disable_tl_uapsd(pQosContext);
806
807 break;
808
809 case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
810 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
811 "%s: Release is complete", __func__);
812
813 if (pCurrentQosInfo) {
814 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
815 "%s: flows still active", __func__);
816
817 /* there is still at least one flow active for
818 * this AC so update the AC state
819 */
820 memcpy(&pAc->wmmAcTspecInfo,
821 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
822
823 /* need to tell TL to update its UAPSD handling */
824 hdd_wmm_enable_tl_uapsd(pQosContext);
825 } else {
826 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
827 "%s: last flow", __func__);
828
829 /* this is the last flow active for this AC so
830 * update the AC state
831 */
832 pAc->wmmAcTspecValid = false;
833
834 /* DELTS is successful, do not allow */
835 pAc->wmmAcAccessAllowed = false;
836
837 /* need to tell TL to update its UAPSD handling */
838 hdd_wmm_disable_tl_uapsd(pQosContext);
839 }
840
841 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
842 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
843 "%s: Explicit Qos, notifying user space",
844 __func__);
845
846 /* this was triggered by an application */
847 pQosContext->lastStatus =
848 HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
849 hdd_wmm_notify_app(pQosContext);
850 }
851 /* we are done with this flow */
852 hdd_wmm_free_context(pQosContext);
853 break;
854
855 case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
856 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
857 "%s: Release failure", __func__);
858
859 /* we don't need to update our state or TL since
860 * nothing has changed
861 */
862 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
863 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
864 "%s: Explicit Qos, notifying user space",
865 __func__);
866
867 /* this was triggered by an application */
868 pQosContext->lastStatus =
869 HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
870 hdd_wmm_notify_app(pQosContext);
871 }
872
873 break;
874
875 case SME_QOS_STATUS_RELEASE_QOS_LOST_IND:
876 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
877 "%s: QOS Lost indication received", __func__);
878
879 /* current TSPEC is no longer valid */
880 pAc->wmmAcTspecValid = false;
881 /* AP has sent DELTS, do not allow */
882 pAc->wmmAcAccessAllowed = false;
883
884 /* need to tell TL to update its UAPSD handling */
885 hdd_wmm_disable_tl_uapsd(pQosContext);
886
887 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
888 /* we no longer have implicit access granted */
889 pAc->wmmAcAccessGranted = false;
890 pAc->wmmAcAccessFailed = false;
891 } else {
892 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
893 "%s: Explicit Qos, notifying user space",
894 __func__);
895
896 /* this was triggered by an application */
897 pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_LOST;
898 hdd_wmm_notify_app(pQosContext);
899 }
900
901 /* we are done with this flow */
902 hdd_wmm_free_context(pQosContext);
903 break;
904
905 case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
906 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
907 "%s: Release pending", __func__);
908 /* not a callback status -- ignore if we get it */
909 break;
910
911 case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
912 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
913 "%s: Release Invalid Params", __func__);
914 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
915 /* this was triggered by an application */
916 pQosContext->lastStatus =
917 HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
918 hdd_wmm_notify_app(pQosContext);
919 }
920 break;
921
922 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND:
923 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
924 "%s: Modification is complete, notify TL", __func__);
925
926 /* there will always be a TSPEC returned with this
927 * status, even if a TSPEC is not exchanged OTA
928 */
929 if (pCurrentQosInfo) {
930 pAc->wmmAcTspecValid = true;
931 memcpy(&pAc->wmmAcTspecInfo,
932 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
933 }
934
935 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
936 /* this was triggered by an application */
937 pQosContext->lastStatus =
938 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS;
939 hdd_wmm_notify_app(pQosContext);
940 }
941 /* notify TL to enable trigger frames if necessary */
942 hdd_wmm_enable_tl_uapsd(pQosContext);
943
944 break;
945
946 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
947 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
948 /* this was triggered by an application */
949 pQosContext->lastStatus =
950 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
951 hdd_wmm_notify_app(pQosContext);
952 }
953 break;
954
955 case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
956 /* the flow modification failed so we'll leave in
957 * place whatever existed beforehand
958 */
959
960 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
961 /* this was triggered by an application */
962 pQosContext->lastStatus =
963 HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
964 hdd_wmm_notify_app(pQosContext);
965 }
966 break;
967
968 case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
969 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
970 "%s: modification pending", __func__);
971 /* not a callback status -- ignore if we get it */
972 break;
973
974 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
975 /* the flow modification was successful but no QoS
976 * changes required
977 */
978
979 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
980 /* this was triggered by an application */
981 pQosContext->lastStatus =
982 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
983 hdd_wmm_notify_app(pQosContext);
984 }
985 break;
986
987 case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
988 /* invalid params -- notify the application */
989 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
990 /* this was triggered by an application */
991 pQosContext->lastStatus =
992 HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
993 hdd_wmm_notify_app(pQosContext);
994 }
995 break;
996
997 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING:
998 /* nothing to do for now. when APSD is established we'll have work to do */
999 break;
1000
1001 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED:
1002 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1003 "%s: Modify successful but U-APSD failed", __func__);
1004
1005 /* QoS modification was successful but setting U=APSD
1006 * failed. This will always be an explicit QoS
1007 * instance, so all we can do is notify the
1008 * application and let it clean up.
1009 */
1010 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
1011 /* this was triggered by an application */
1012 pQosContext->lastStatus =
1013 HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED;
1014 hdd_wmm_notify_app(pQosContext);
1015 }
1016 /* Since U-APSD portion failed disabled trigger frame
1017 * generation
1018 */
1019 hdd_wmm_disable_tl_uapsd(pQosContext);
1020
1021 break;
1022
1023 case SME_QOS_STATUS_HANDING_OFF:
1024 /* no roaming so we won't see this */
1025 break;
1026
1027 case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND:
1028 /* need to tell TL to stop trigger frame generation */
1029 hdd_wmm_disable_tl_uapsd(pQosContext);
1030 break;
1031
1032 case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND:
1033 /* need to tell TL to start sending trigger frames again */
1034 hdd_wmm_enable_tl_uapsd(pQosContext);
1035 break;
1036
1037 default:
1038 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1039 "%s: unexpected SME Status=%d", __func__, smeStatus);
1040 CDF_ASSERT(0);
1041 }
1042
1043 /* if Tspec only allows downstream traffic then access is not
1044 * allowed
1045 */
1046 if (pAc->wmmAcTspecValid &&
1047 (pAc->wmmAcTspecInfo.ts_info.direction ==
1048 SME_QOS_WMM_TS_DIR_DOWNLINK)) {
1049 pAc->wmmAcAccessAllowed = false;
1050 }
1051 /* if we have valid Tpsec or if ACM bit is not set, allow access */
1052 if ((pAc->wmmAcTspecValid &&
1053 (pAc->wmmAcTspecInfo.ts_info.direction !=
1054 SME_QOS_WMM_TS_DIR_DOWNLINK)) || !pAc->wmmAcAccessRequired) {
1055 pAc->wmmAcAccessAllowed = true;
1056 }
1057
1058 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
1059 "%s: complete, access for TL AC %d is%sallowed",
1060 __func__, acType, pAc->wmmAcAccessAllowed ? " " : " not ");
1061
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301062 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001063}
1064#endif
1065
1066/**
1067 * hdd_wmmps_helper() - Function to set uapsd psb dynamically
1068 *
1069 * @pAdapter: [in] pointer to adapter structure
1070 * @ptr: [in] pointer to command buffer
1071 *
1072 * Return: Zero on success, appropriate error on failure.
1073 */
1074int hdd_wmmps_helper(hdd_adapter_t *pAdapter, uint8_t *ptr)
1075{
1076 if (NULL == pAdapter) {
1077 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1078 "%s: pAdapter is NULL", __func__);
1079 return -EINVAL;
1080 }
1081 if (NULL == ptr) {
1082 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1083 "%s: ptr is NULL", __func__);
1084 return -EINVAL;
1085 }
1086 /* convert ASCII to integer */
1087 pAdapter->configuredPsb = ptr[9] - '0';
1088 pAdapter->psbChanged = HDD_PSB_CHANGED;
1089
1090 return 0;
1091}
1092
1093/**
1094 * __hdd_wmm_do_implicit_qos() - Function which will attempt to setup
1095 * QoS for any AC requiring it.
1096 * @work: [in] pointer to work structure.
1097 *
1098 * Return: none
1099 */
1100static void __hdd_wmm_do_implicit_qos(struct work_struct *work)
1101{
1102 hdd_wmm_qos_context_t *pQosContext =
1103 container_of(work, hdd_wmm_qos_context_t, wmmAcSetupImplicitQos);
1104 hdd_adapter_t *pAdapter;
1105 sme_ac_enum_type acType;
1106 hdd_wmm_ac_status_t *pAc;
1107#ifndef WLAN_MDM_CODE_REDUCTION_OPT
1108 sme_QosStatusType smeStatus;
1109#endif
1110 sme_QosWmmTspecInfo qosInfo;
1111 hdd_context_t *hdd_ctx;
1112
1113 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1114 "%s: Entered, context %p", __func__, pQosContext);
1115
1116 if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic)) {
1117 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1118 "%s: Invalid QoS Context", __func__);
1119 return;
1120 }
1121
1122 pAdapter = pQosContext->pAdapter;
1123
1124 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
1125 if (0 != wlan_hdd_validate_context(hdd_ctx)) {
1126 hddLog(LOGE, FL("HDD context is not valid"));
1127 return;
1128 }
1129
1130 acType = pQosContext->acType;
1131 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1132
1133 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1134 "%s: pAdapter %p acType %d", __func__, pAdapter, acType);
1135
1136 if (!pAc->wmmAcAccessNeeded) {
1137 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1138 "%s: AC %d doesn't need service", __func__, acType);
1139 pQosContext->magic = 0;
1140 kfree(pQosContext);
1141 return;
1142 }
1143
1144 pAc->wmmAcAccessPending = true;
1145 pAc->wmmAcAccessNeeded = false;
1146
1147 memset(&qosInfo, 0, sizeof(qosInfo));
1148
1149 qosInfo.ts_info.psb = pAdapter->configuredPsb;
1150
1151 switch (acType) {
1152 case SME_AC_VO:
1153 qosInfo.ts_info.up = SME_QOS_WMM_UP_VO;
1154 /* Check if there is any valid configuration from framework */
1155 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1156 qosInfo.ts_info.psb =
1157 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1158 UapsdMask & SME_QOS_UAPSD_VO) ? 1 : 0;
1159 }
1160 qosInfo.ts_info.direction =
1161 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVo;
1162 qosInfo.ts_info.tid = 255;
1163 qosInfo.mean_data_rate =
1164 (WLAN_HDD_GET_CTX(pAdapter))->config->
1165 InfraMeanDataRateAcVo;
1166 qosInfo.min_phy_rate =
1167 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVo;
1168 qosInfo.min_service_interval =
1169 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSrvIntv;
1170 qosInfo.nominal_msdu_size =
1171 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVo;
1172 qosInfo.surplus_bw_allowance =
1173 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVo;
1174 qosInfo.suspension_interval =
1175 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSuspIntv;
1176 break;
1177 case SME_AC_VI:
1178 qosInfo.ts_info.up = SME_QOS_WMM_UP_VI;
1179 /* Check if there is any valid configuration from framework */
1180 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1181 qosInfo.ts_info.psb =
1182 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1183 UapsdMask & SME_QOS_UAPSD_VI) ? 1 : 0;
1184 }
1185 qosInfo.ts_info.direction =
1186 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVi;
1187 qosInfo.ts_info.tid = 255;
1188 qosInfo.mean_data_rate =
1189 (WLAN_HDD_GET_CTX(pAdapter))->config->
1190 InfraMeanDataRateAcVi;
1191 qosInfo.min_phy_rate =
1192 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVi;
1193 qosInfo.min_service_interval =
1194 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSrvIntv;
1195 qosInfo.nominal_msdu_size =
1196 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVi;
1197 qosInfo.surplus_bw_allowance =
1198 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVi;
1199 qosInfo.suspension_interval =
1200 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSuspIntv;
1201 break;
1202 default:
1203 case SME_AC_BE:
1204 qosInfo.ts_info.up = SME_QOS_WMM_UP_BE;
1205 /* Check if there is any valid configuration from framework */
1206 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1207 qosInfo.ts_info.psb =
1208 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1209 UapsdMask & SME_QOS_UAPSD_BE) ? 1 : 0;
1210 }
1211 qosInfo.ts_info.direction =
1212 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBe;
1213 qosInfo.ts_info.tid = 255;
1214 qosInfo.mean_data_rate =
1215 (WLAN_HDD_GET_CTX(pAdapter))->config->
1216 InfraMeanDataRateAcBe;
1217 qosInfo.min_phy_rate =
1218 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBe;
1219 qosInfo.min_service_interval =
1220 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSrvIntv;
1221 qosInfo.nominal_msdu_size =
1222 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBe;
1223 qosInfo.surplus_bw_allowance =
1224 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBe;
1225 qosInfo.suspension_interval =
1226 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSuspIntv;
1227 break;
1228 case SME_AC_BK:
1229 qosInfo.ts_info.up = SME_QOS_WMM_UP_BK;
1230 /* Check if there is any valid configuration from framework */
1231 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1232 qosInfo.ts_info.psb =
1233 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1234 UapsdMask & SME_QOS_UAPSD_BK) ? 1 : 0;
1235 }
1236 qosInfo.ts_info.direction =
1237 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBk;
1238 qosInfo.ts_info.tid = 255;
1239 qosInfo.mean_data_rate =
1240 (WLAN_HDD_GET_CTX(pAdapter))->config->
1241 InfraMeanDataRateAcBk;
1242 qosInfo.min_phy_rate =
1243 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBk;
1244 qosInfo.min_service_interval =
1245 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSrvIntv;
1246 qosInfo.nominal_msdu_size =
1247 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBk;
1248 qosInfo.surplus_bw_allowance =
1249 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBk;
1250 qosInfo.suspension_interval =
1251 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSuspIntv;
1252 break;
1253 }
1254#ifdef FEATURE_WLAN_ESE
1255 qosInfo.inactivity_interval =
1256 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraInactivityInterval;
1257#endif
1258 qosInfo.ts_info.burst_size_defn =
1259 (WLAN_HDD_GET_CTX(pAdapter))->config->burstSizeDefinition;
1260
1261 switch ((WLAN_HDD_GET_CTX(pAdapter))->config->tsInfoAckPolicy) {
1262 case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK:
1263 qosInfo.ts_info.ack_policy =
1264 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1265 break;
1266
1267 case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK:
1268 qosInfo.ts_info.ack_policy =
1269 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK;
1270 break;
1271
1272 default:
1273 /* unknown */
1274 qosInfo.ts_info.ack_policy =
1275 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1276 }
1277
1278 if (qosInfo.ts_info.ack_policy ==
1279 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) {
1280 if (!sme_qos_is_ts_info_ack_policy_valid
1281 ((tpAniSirGlobal) WLAN_HDD_GET_HAL_CTX(pAdapter), &qosInfo,
1282 pAdapter->sessionId)) {
1283 qosInfo.ts_info.ack_policy =
1284 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1285 }
1286 }
1287
1288 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
1289 list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList);
1290 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
1291
1292#ifndef WLAN_MDM_CODE_REDUCTION_OPT
1293 smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
1294 pAdapter->sessionId,
1295 &qosInfo,
1296 hdd_wmm_sme_callback,
1297 pQosContext,
1298 qosInfo.ts_info.up,
1299 &pQosContext->qosFlowId);
1300
1301 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
1302 "%s: sme_qos_setup_req returned %d flowid %d",
1303 __func__, smeStatus, pQosContext->qosFlowId);
1304
1305 /* need to check the return values and act appropriately */
1306 switch (smeStatus) {
1307 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
1308 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
1309 /* setup is pending, so no more work to do now. all
1310 * further work will be done in hdd_wmm_sme_callback()
1311 */
1312 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1313 "%s: Setup is pending, no further work", __func__);
1314
1315 break;
1316
1317 case SME_QOS_STATUS_SETUP_FAILURE_RSP:
1318 /* we can't tell the difference between when a request
1319 * fails because AP rejected it versus when SME
1320 * encountered an internal error. in either case SME
1321 * won't ever reference this context so free the
1322 * record
1323 */
1324 hdd_wmm_free_context(pQosContext);
1325
1326 /* fall through and start packets flowing */
1327 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
1328 /* no ACM in effect, no need to setup U-APSD */
1329 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
1330 /* no ACM in effect, U-APSD is desired but was already setup */
1331
1332 /* for these cases everything is already setup so we
1333 * can signal TL that it has work to do
1334 */
1335 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1336 "%s: Setup is complete, notify TL", __func__);
1337
1338 pAc->wmmAcAccessAllowed = true;
1339 pAc->wmmAcAccessGranted = true;
1340 pAc->wmmAcAccessPending = false;
1341
1342 break;
1343
1344 default:
1345 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1346 "%s: unexpected SME Status=%d", __func__, smeStatus);
1347 CDF_ASSERT(0);
1348 }
1349#endif
1350
1351}
1352
1353/**
1354 * hdd_wmm_do_implicit_qos() - SSR wraper function for hdd_wmm_do_implicit_qos
1355 * @work: pointer to work_struct
1356 *
1357 * Return: none
1358 */
1359static void hdd_wmm_do_implicit_qos(struct work_struct *work)
1360{
1361 cds_ssr_protect(__func__);
1362 __hdd_wmm_do_implicit_qos(work);
1363 cds_ssr_unprotect(__func__);
1364}
1365
1366/**
1367 * hdd_wmm_init() - initialize the WMM DSCP configuation
1368 * @pAdapter : [in] pointer to Adapter context
1369 *
1370 * This function will initialize the WMM DSCP configuation of an
1371 * adapter to an initial state. The configuration can later be
1372 * overwritten via application APIs or via QoS Map sent OTA.
1373 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301374 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001375 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301376QDF_STATUS hdd_wmm_init(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001377{
1378 sme_QosWmmUpType *hddWmmDscpToUpMap = pAdapter->hddWmmDscpToUpMap;
1379 uint8_t dscp;
1380
1381 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1382 "%s: Entered", __func__);
1383
1384 /* DSCP to User Priority Lookup Table
1385 * By default use the 3 Precedence bits of DSCP as the User Priority
1386 */
1387 for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++) {
1388 hddWmmDscpToUpMap[dscp] = dscp >> 3;
1389 }
1390
1391 /* Special case for Expedited Forwarding (DSCP 46) */
1392 hddWmmDscpToUpMap[46] = SME_QOS_WMM_UP_VO;
1393
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301394 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001395}
1396
1397/**
1398 * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter
1399 * @pAdapter: [in] pointer to Adapter context
1400 *
1401 * This function will initialize the WMM configuation and status of an
1402 * adapter to an initial state. The configuration can later be
1403 * overwritten via application APIs
1404 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301405 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001406 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301407QDF_STATUS hdd_wmm_adapter_init(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001408{
1409 hdd_wmm_ac_status_t *pAcStatus;
1410 sme_ac_enum_type acType;
1411
1412 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1413 "%s: Entered", __func__);
1414
1415 pAdapter->hddWmmStatus.wmmQap = false;
1416 INIT_LIST_HEAD(&pAdapter->hddWmmStatus.wmmContextList);
1417 mutex_init(&pAdapter->hddWmmStatus.wmmLock);
1418
1419 for (acType = 0; acType < WLAN_MAX_AC; acType++) {
1420 pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1421 pAcStatus->wmmAcAccessRequired = false;
1422 pAcStatus->wmmAcAccessNeeded = false;
1423 pAcStatus->wmmAcAccessPending = false;
1424 pAcStatus->wmmAcAccessFailed = false;
1425 pAcStatus->wmmAcAccessGranted = false;
1426 pAcStatus->wmmAcAccessAllowed = false;
1427 pAcStatus->wmmAcTspecValid = false;
1428 pAcStatus->wmmAcUapsdInfoValid = false;
1429 }
1430 /* Invalid value(0xff) to indicate psb not configured through
1431 * framework initially.
1432 */
1433 pAdapter->configuredPsb = HDD_PSB_CFG_INVALID;
1434
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301435 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436}
1437
1438/**
1439 * hdd_wmm_adapter_clear() - Function which will clear the WMM status
1440 * for all the ACs
1441 *
1442 * @pAdapter: [in] pointer to Adapter context
1443 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301444 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301446QDF_STATUS hdd_wmm_adapter_clear(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001447{
1448 hdd_wmm_ac_status_t *pAcStatus;
1449 sme_ac_enum_type acType;
1450 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1451 "%s: Entered", __func__);
1452 for (acType = 0; acType < WLAN_MAX_AC; acType++) {
1453 pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1454 pAcStatus->wmmAcAccessRequired = false;
1455 pAcStatus->wmmAcAccessNeeded = false;
1456 pAcStatus->wmmAcAccessPending = false;
1457 pAcStatus->wmmAcAccessFailed = false;
1458 pAcStatus->wmmAcAccessGranted = false;
1459 pAcStatus->wmmAcAccessAllowed = false;
1460 pAcStatus->wmmAcTspecValid = false;
1461 pAcStatus->wmmAcUapsdInfoValid = false;
1462 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301463 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464}
1465
1466/**
1467 * hdd_wmm_close() - WMM close function
1468 * @pAdapter: [in] pointer to adapter context
1469 *
1470 * Function which will perform any necessary work to to clean up the
1471 * WMM functionality prior to the kernel module unload.
1472 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301473 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301475QDF_STATUS hdd_wmm_adapter_close(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001476{
1477 hdd_wmm_qos_context_t *pQosContext;
1478
1479 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1480 "%s: Entered", __func__);
1481
1482 /* free any context records that we still have linked */
1483 while (!list_empty(&pAdapter->hddWmmStatus.wmmContextList)) {
1484 pQosContext =
1485 list_first_entry(&pAdapter->hddWmmStatus.wmmContextList,
1486 hdd_wmm_qos_context_t, node);
1487#ifdef FEATURE_WLAN_ESE
1488 hdd_wmm_disable_inactivity_timer(pQosContext);
1489#endif
1490 if (pQosContext->handle == HDD_WMM_HANDLE_IMPLICIT
1491 && pQosContext->magic == HDD_WMM_CTX_MAGIC)
1492 cds_flush_work(&pQosContext->wmmAcSetupImplicitQos);
1493
1494 hdd_wmm_free_context(pQosContext);
1495 }
1496
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301497 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001498}
1499
1500/**
1501 * hdd_wmm_classify_pkt() - Function which will classify an OS packet
Govind Singhb7ab5772015-10-08 16:38:37 +05301502 * into a WMM AC based on DSCP
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001503 *
Govind Singhb7ab5772015-10-08 16:38:37 +05301504 * @adapter: adapter upon which the packet is being transmitted
1505 * @skb: pointer to network buffer
1506 * @user_pri: user priority of the OS packet
1507 * @is_eapol: eapol packet flag
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001508 *
1509 * Return: None
1510 */
1511static
Govind Singhb7ab5772015-10-08 16:38:37 +05301512void hdd_wmm_classify_pkt(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513 struct sk_buff *skb,
Govind Singhb7ab5772015-10-08 16:38:37 +05301514 sme_QosWmmUpType *user_pri,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001515 bool *is_eapol)
1516{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001517 unsigned char dscp;
Govind Singhb7ab5772015-10-08 16:38:37 +05301518 unsigned char tos;
1519 union generic_ethhdr *eth_hdr;
1520 struct iphdr *ip_hdr;
1521 struct ipv6hdr *ipv6hdr;
1522 unsigned char *pkt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523
1524 /* this code is executed for every packet therefore
1525 * all debug code is kept conditional
1526 */
1527
1528#ifdef HDD_WMM_DEBUG
1529 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1530 "%s: Entered", __func__);
1531#endif /* HDD_WMM_DEBUG */
1532
Govind Singhb7ab5772015-10-08 16:38:37 +05301533 pkt = skb->data;
1534 eth_hdr = (union generic_ethhdr *)pkt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001535
1536#ifdef HDD_WMM_DEBUG
1537 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Govind Singhb7ab5772015-10-08 16:38:37 +05301538 "%s: proto is 0x%04x", __func__, skb->protocol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001539#endif /* HDD_WMM_DEBUG */
1540
Govind Singhb7ab5772015-10-08 16:38:37 +05301541 if (eth_hdr->eth_II.h_proto == htons(ETH_P_IP)) {
1542 /* case 1: Ethernet II IP packet */
1543 ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_II)];
1544 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001545#ifdef HDD_WMM_DEBUG
Govind Singhb7ab5772015-10-08 16:38:37 +05301546 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1547 "%s: Ethernet II IP Packet, tos is %d",
1548 __func__, tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001549#endif /* HDD_WMM_DEBUG */
1550
Govind Singhb7ab5772015-10-08 16:38:37 +05301551 } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) {
1552 ipv6hdr = ipv6_hdr(skb);
1553 tos = ntohs(*(const __be16 *)ipv6hdr) >> 4;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001554#ifdef HDD_WMM_DEBUG
Govind Singhb7ab5772015-10-08 16:38:37 +05301555 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1556 "%s: Ethernet II IPv6 Packet, tos is %d",
1557 __func__, tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001558#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301559 } else if ((ntohs(eth_hdr->eth_II.h_proto) < WLAN_MIN_PROTO) &&
1560 (eth_hdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) &&
1561 (eth_hdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) &&
1562 (eth_hdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) &&
1563 (eth_hdr->eth_8023.h_proto == htons(ETH_P_IP))) {
1564 /* case 2: 802.3 LLC/SNAP IP packet */
1565 ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_8023)];
1566 tos = ip_hdr->tos;
1567#ifdef HDD_WMM_DEBUG
1568 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1569 "%s: 802.3 LLC/SNAP IP Packet, tos is %d",
1570 __func__, tos);
1571#endif /* HDD_WMM_DEBUG */
1572 } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) {
1573 /* VLAN tagged */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001574
Govind Singhb7ab5772015-10-08 16:38:37 +05301575 if (eth_hdr->eth_IIv.h_vlan_encapsulated_proto ==
1576 htons(ETH_P_IP)) {
1577 /* case 3: Ethernet II vlan-tagged IP packet */
1578 ip_hdr =
1579 (struct iphdr *)
1580 &pkt[sizeof(eth_hdr->eth_IIv)];
1581 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001582#ifdef HDD_WMM_DEBUG
Govind Singhb7ab5772015-10-08 16:38:37 +05301583 CDF_TRACE(CDF_MODULE_ID_HDD,
1584 WMM_TRACE_LEVEL_INFO_LOW,
1585 "%s: Ethernet II VLAN tagged IP Packet, tos is %d",
1586 __func__, tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001587#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301588 } else
1589 if ((ntohs(eth_hdr->eth_IIv.h_vlan_encapsulated_proto)
1590 < WLAN_MIN_PROTO)
1591 && (eth_hdr->eth_8023v.h_snap.dsap ==
1592 WLAN_SNAP_DSAP)
1593 && (eth_hdr->eth_8023v.h_snap.ssap ==
1594 WLAN_SNAP_SSAP)
1595 && (eth_hdr->eth_8023v.h_snap.ctrl ==
1596 WLAN_SNAP_CTRL)
1597 && (eth_hdr->eth_8023v.h_proto ==
1598 htons(ETH_P_IP))) {
1599 /* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */
1600 ip_hdr =
1601 (struct iphdr *)
1602 &pkt[sizeof(eth_hdr->eth_8023v)];
1603 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001604#ifdef HDD_WMM_DEBUG
Govind Singhb7ab5772015-10-08 16:38:37 +05301605 CDF_TRACE(CDF_MODULE_ID_HDD,
1606 WMM_TRACE_LEVEL_INFO_LOW,
1607 "%s: 802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d",
1608 __func__, tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001609#endif /* HDD_WMM_DEBUG */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001610 } else {
1611 /* default */
1612#ifdef HDD_WMM_DEBUG
Govind Singhb7ab5772015-10-08 16:38:37 +05301613 CDF_TRACE(CDF_MODULE_ID_HDD,
1614 WMM_TRACE_LEVEL_WARN,
1615 "%s: VLAN tagged Unhandled Protocol, using default tos",
1616 __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301618 tos = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001619 }
1620 } else {
1621 /* default */
1622#ifdef HDD_WMM_DEBUG
Govind Singhb7ab5772015-10-08 16:38:37 +05301623 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN,
1624 "%s: Unhandled Protocol, using default tos",
1625 __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301627 /* Give the highest priority to 802.1x packet */
1628 if (eth_hdr->eth_II.h_proto ==
1629 htons(HDD_ETHERTYPE_802_1_X)) {
1630 tos = 0xC0;
1631 *is_eapol = true;
1632 } else
1633 tos = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634 }
1635
Govind Singhb7ab5772015-10-08 16:38:37 +05301636 dscp = (tos >> 2) & 0x3f;
1637 *user_pri = adapter->hddWmmDscpToUpMap[dscp];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638
1639#ifdef HDD_WMM_DEBUG
1640 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Govind Singhb7ab5772015-10-08 16:38:37 +05301641 "%s: tos is %d, dscp is %d, up is %d",
1642 __func__, tos, dscp, *user_pri);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643#endif /* HDD_WMM_DEBUG */
1644
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645 return;
1646}
1647
1648#ifdef QCA_LL_TX_FLOW_CONTROL_V2
1649/**
1650 * hdd_get_queue_index() - get queue index
1651 * @up: user priority
1652 * @is_eapol: is_eapol flag
1653 *
1654 * Return: queue_index
1655 */
1656static
1657uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol)
1658{
1659 if (cdf_unlikely(is_eapol == true))
1660 return HDD_LINUX_AC_HI_PRIO;
1661 else
1662 return hdd_linux_up_to_ac_map[up];
1663}
1664#else
1665static
1666uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol)
1667{
1668 return hdd_linux_up_to_ac_map[up];
1669}
1670#endif
1671
1672
1673/**
1674 * hdd_hostapd_select_queue() - Function which will classify the packet
1675 * according to linux qdisc expectation.
1676 *
1677 * @dev: [in] pointer to net_device structure
1678 * @skb: [in] pointer to os packet
1679 *
1680 * Return: Qdisc queue index
1681 */
1682uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb
1683#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
1684 , void *accel_priv
1685#endif
1686#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1687 , select_queue_fallback_t fallback
1688#endif
1689
1690)
1691{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692 sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
1693 uint16_t queueIndex;
Govind Singhb7ab5772015-10-08 16:38:37 +05301694 hdd_adapter_t *adapter = (hdd_adapter_t *) netdev_priv(dev);
1695 hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001696 bool is_eapol = false;
Mukul Sharmab3152182015-10-30 20:47:30 +05301697 int status = 0;
Govind Singhb7ab5772015-10-08 16:38:37 +05301698 status = wlan_hdd_validate_context(hddctx);
Mukul Sharmab3152182015-10-30 20:47:30 +05301699
1700 if (status != 0) {
1701 skb->priority = SME_QOS_WMM_UP_BE;
1702 return HDD_LINUX_AC_BE;
1703 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704
Govind Singhb7ab5772015-10-08 16:38:37 +05301705 /* Get the user priority from IP header */
1706 hdd_wmm_classify_pkt(adapter, skb, &up, &is_eapol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001707 skb->priority = up;
1708 queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
1709
1710 return queueIndex;
1711}
1712
1713/**
1714 * hdd_wmm_select_queue() - Function which will classify the packet
1715 * according to linux qdisc expectation.
1716 *
1717 * @dev: [in] pointer to net_device structure
1718 * @skb: [in] pointer to os packet
1719 *
1720 * Return: Qdisc queue index
1721 */
1722uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb)
1723{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001724 sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
1725 uint16_t queueIndex;
1726 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1727 bool is_eapol = false;
Mukul Sharmabfd19ba2015-10-30 20:35:35 +05301728 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
1729 int status;
1730
1731 status = wlan_hdd_validate_context(hdd_ctx);
1732 if (status != 0) {
1733 skb->priority = SME_QOS_WMM_UP_BE;
1734 return HDD_LINUX_AC_BE;
1735 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001736
Govind Singhb7ab5772015-10-08 16:38:37 +05301737 /* Get the user priority from IP header */
1738 hdd_wmm_classify_pkt(pAdapter, skb, &up, &is_eapol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001739 skb->priority = up;
1740 queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
Govind Singhb7ab5772015-10-08 16:38:37 +05301741
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001742 return queueIndex;
1743}
1744
1745/**
1746 * hdd_wmm_acquire_access_required() - Function which will determine
1747 * acquire admittance for a WMM AC is required or not based on psb configuration
1748 * done in framework
1749 *
1750 * @pAdapter: [in] pointer to adapter structure
1751 * @acType: [in] WMM AC type of OS packet
1752 *
1753 * Return: void
1754 */
1755void hdd_wmm_acquire_access_required(hdd_adapter_t *pAdapter,
1756 sme_ac_enum_type acType)
1757{
1758 /* Each bit in the LSB nibble indicates 1 AC.
1759 * Clearing the particular bit in LSB nibble to indicate
1760 * access required
1761 */
1762 switch (acType) {
1763 case SME_AC_BK:
1764 /* clear first bit */
1765 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK;
1766 break;
1767 case SME_AC_BE:
1768 /* clear second bit */
1769 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK;
1770 break;
1771 case SME_AC_VI:
1772 /* clear third bit */
1773 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK;
1774 break;
1775 case SME_AC_VO:
1776 /* clear fourth bit */
1777 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK;
1778 break;
1779 default:
1780 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1781 "%s: Invalid AC Type", __func__);
1782 break;
1783 }
1784}
1785
1786/**
1787 * hdd_wmm_acquire_access() - Function which will attempt to acquire
1788 * admittance for a WMM AC
1789 *
1790 * @pAdapter: [in] pointer to adapter context
1791 * @acType: [in] WMM AC type of OS packet
1792 * @pGranted: [out] pointer to bool flag when indicates if access
1793 * has been granted or not
1794 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301795 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001796 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301797QDF_STATUS hdd_wmm_acquire_access(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798 sme_ac_enum_type acType, bool *pGranted)
1799{
1800 hdd_wmm_qos_context_t *pQosContext;
1801
1802 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1803 "%s: Entered for AC %d", __func__, acType);
1804
1805 if (!hdd_wmm_is_active(pAdapter) ||
1806 !(WLAN_HDD_GET_CTX(pAdapter))->config->bImplicitQosEnabled ||
1807 !pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessRequired) {
1808 /* either we don't want QoS or the AP doesn't support
1809 * QoS or we don't want to do implicit QoS
1810 */
1811 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1812 "%s: QoS not configured on both ends ", __func__);
1813
1814 *pGranted =
1815 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1816 wmmAcAccessAllowed;
1817
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301818 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001819 }
1820 /* do we already have an implicit QoS request pending for this AC? */
1821 if ((pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded) ||
1822 (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessPending)) {
1823 /* request already pending so we need to wait for that
1824 * response
1825 */
1826 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1827 "%s: Implicit QoS for TL AC %d already scheduled",
1828 __func__, acType);
1829
1830 *pGranted = false;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301831 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832 }
1833 /* did we already fail to establish implicit QoS for this AC?
1834 * (if so, access should have been granted when the failure
1835 * was handled)
1836 */
1837 if (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessFailed) {
1838 /* request previously failed
1839 * allow access, but we'll be downgraded
1840 */
1841 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1842 "%s: Implicit QoS for TL AC %d previously failed",
1843 __func__, acType);
1844
1845 if (!pAdapter->hddWmmStatus.wmmAcStatus[acType].
1846 wmmAcAccessRequired) {
1847 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1848 wmmAcAccessAllowed = true;
1849 *pGranted = true;
1850 } else {
1851 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1852 wmmAcAccessAllowed = false;
1853 *pGranted = false;
1854 }
1855
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301856 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001857 }
1858 /* we need to establish implicit QoS */
1859 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
1860 "%s: Need to schedule implicit QoS for TL AC %d, pAdapter is %p",
1861 __func__, acType, pAdapter);
1862
1863 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded = true;
1864
1865 pQosContext = kmalloc(sizeof(*pQosContext), GFP_ATOMIC);
1866 if (NULL == pQosContext) {
1867 /* no memory for QoS context. Nothing we can do but
1868 * let data flow
1869 */
1870 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
1871 "%s: Unable to allocate context", __func__);
1872 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed =
1873 true;
1874 *pGranted = true;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301875 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001876 }
1877
1878 pQosContext->acType = acType;
1879 pQosContext->pAdapter = pAdapter;
1880 pQosContext->qosFlowId = 0;
1881 pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT;
1882 pQosContext->magic = HDD_WMM_CTX_MAGIC;
1883 pQosContext->is_inactivity_timer_running = false;
1884
1885#ifdef CONFIG_CNSS
1886 cnss_init_work(&pQosContext->wmmAcSetupImplicitQos,
1887 hdd_wmm_do_implicit_qos);
1888#else
1889 INIT_WORK(&pQosContext->wmmAcSetupImplicitQos, hdd_wmm_do_implicit_qos);
1890#endif
1891
1892 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
1893 "%s: Scheduling work for AC %d, context %p",
1894 __func__, acType, pQosContext);
1895
1896 schedule_work(&pQosContext->wmmAcSetupImplicitQos);
1897
1898 /* caller will need to wait until the work takes place and
1899 * TSPEC negotiation completes
1900 */
1901 *pGranted = false;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301902 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903}
1904
1905/**
1906 * hdd_wmm_assoc() - Function which will handle the housekeeping
1907 * required by WMM when association takes place
1908 *
1909 * @pAdapter: [in] pointer to adapter context
1910 * @pRoamInfo: [in] pointer to roam information
1911 * @eBssType: [in] type of BSS
1912 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301913 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001914 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301915QDF_STATUS hdd_wmm_assoc(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001916 tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType)
1917{
1918 uint8_t uapsdMask;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301919 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001920 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1921
1922 /* when we associate we need to notify TL if it needs to
1923 * enable UAPSD for any access categories
1924 */
1925
1926 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1927 "%s: Entered", __func__);
1928
1929 if (pRoamInfo->fReassocReq) {
1930 /* when we reassociate we should continue to use
1931 * whatever parameters were previously established.
1932 * if we are reassociating due to a U-APSD change for
1933 * a particular Access Category, then the change will
1934 * be communicated to HDD via the QoS callback
1935 * associated with the given flow, and U-APSD
1936 * parameters will be updated there
1937 */
1938
1939 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1940 "%s: Reassoc so no work, Exiting", __func__);
1941
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301942 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001943 }
1944 /* get the negotiated UAPSD Mask */
1945 uapsdMask =
1946 pRoamInfo->u.pConnectedProfile->modifyProfileFields.uapsd_mask;
1947
1948 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
1949 "%s: U-APSD mask is 0x%02x", __func__, (int)uapsdMask);
1950
1951 if (uapsdMask & HDD_AC_VO) {
1952 status =
1953 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1954 pcds_context,
1955 (WLAN_HDD_GET_STATION_CTX_PTR
1956 (pAdapter))->conn_info.staId[0],
1957 SME_AC_VO, 7, 7,
1958 pHddCtx->config->InfraUapsdVoSrvIntv,
1959 pHddCtx->config->InfraUapsdVoSuspIntv,
1960 SME_BI_DIR, 1,
1961 pAdapter->sessionId,
1962 pHddCtx->config->DelayedTriggerFrmInt);
1963
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301964 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965 }
1966
1967 if (uapsdMask & HDD_AC_VI) {
1968 status =
1969 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1970 pcds_context,
1971 (WLAN_HDD_GET_STATION_CTX_PTR
1972 (pAdapter))->conn_info.staId[0],
1973 SME_AC_VI, 5, 5,
1974 pHddCtx->config->InfraUapsdViSrvIntv,
1975 pHddCtx->config->InfraUapsdViSuspIntv,
1976 SME_BI_DIR, 1,
1977 pAdapter->sessionId,
1978 pHddCtx->config->DelayedTriggerFrmInt);
1979
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301980 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001981 }
1982
1983 if (uapsdMask & HDD_AC_BK) {
1984 status =
1985 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1986 pcds_context,
1987 (WLAN_HDD_GET_STATION_CTX_PTR
1988 (pAdapter))->conn_info.staId[0],
1989 SME_AC_BK, 2, 2,
1990 pHddCtx->config->InfraUapsdBkSrvIntv,
1991 pHddCtx->config->InfraUapsdBkSuspIntv,
1992 SME_BI_DIR, 1,
1993 pAdapter->sessionId,
1994 pHddCtx->config->DelayedTriggerFrmInt);
1995
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301996 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001997 }
1998
1999 if (uapsdMask & HDD_AC_BE) {
2000 status =
2001 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
2002 pcds_context,
2003 (WLAN_HDD_GET_STATION_CTX_PTR
2004 (pAdapter))->conn_info.staId[0],
2005 SME_AC_BE, 3, 3,
2006 pHddCtx->config->InfraUapsdBeSrvIntv,
2007 pHddCtx->config->InfraUapsdBeSuspIntv,
2008 SME_BI_DIR, 1,
2009 pAdapter->sessionId,
2010 pHddCtx->config->DelayedTriggerFrmInt);
2011
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302012 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002013 }
2014
2015 status = sme_update_dsc_pto_up_mapping(pHddCtx->hHal,
2016 pAdapter->hddWmmDscpToUpMap,
2017 pAdapter->sessionId);
2018
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302019 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020 hdd_wmm_init(pAdapter);
2021 }
2022
2023 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2024 "%s: Exiting", __func__);
2025
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302026 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002027}
2028
2029static const uint8_t acm_mask_bit[WLAN_MAX_AC] = {
2030 0x4, /* SME_AC_BK */
2031 0x8, /* SME_AC_BE */
2032 0x2, /* SME_AC_VI */
2033 0x1 /* SME_AC_VO */
2034};
2035
2036/**
2037 * hdd_wmm_connect() - Function which will handle the housekeeping
2038 * required by WMM when a connection is established
2039 *
2040 * @pAdapter : [in] pointer to adapter context
2041 * @pRoamInfo: [in] pointer to roam information
2042 * @eBssType : [in] type of BSS
2043 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302044 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002045 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302046QDF_STATUS hdd_wmm_connect(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002047 tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType)
2048{
2049 int ac;
2050 bool qap;
2051 bool qosConnection;
2052 uint8_t acmMask;
2053
2054 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2055 "%s: Entered", __func__);
2056
2057 if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) &&
2058 pRoamInfo && pRoamInfo->u.pConnectedProfile) {
2059 qap = pRoamInfo->u.pConnectedProfile->qap;
2060 qosConnection = pRoamInfo->u.pConnectedProfile->qosConnection;
2061 acmMask = pRoamInfo->u.pConnectedProfile->acm_mask;
2062 } else {
2063 qap = true;
2064 qosConnection = true;
2065 acmMask = 0x0;
2066 }
2067
2068 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2069 "%s: qap is %d, qosConnection is %d, acmMask is 0x%x",
2070 __func__, qap, qosConnection, acmMask);
2071
2072 pAdapter->hddWmmStatus.wmmQap = qap;
2073 pAdapter->hddWmmStatus.wmmQosConnection = qosConnection;
2074
2075 for (ac = 0; ac < WLAN_MAX_AC; ac++) {
2076 if (qap && qosConnection && (acmMask & acm_mask_bit[ac])) {
2077 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2078 "%s: ac %d on", __func__, ac);
2079
2080 /* admission is required */
2081 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2082 wmmAcAccessRequired = true;
2083 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2084 wmmAcAccessAllowed = false;
2085 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2086 wmmAcAccessGranted = false;
2087 /* after reassoc if we have valid tspec, allow access */
2088 if (pAdapter->hddWmmStatus.wmmAcStatus[ac].
2089 wmmAcTspecValid
2090 && (pAdapter->hddWmmStatus.wmmAcStatus[ac].
2091 wmmAcTspecInfo.ts_info.direction !=
2092 SME_QOS_WMM_TS_DIR_DOWNLINK)) {
2093 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2094 wmmAcAccessAllowed = true;
2095 }
2096 } else {
2097 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2098 "%s: ac %d off", __func__, ac);
2099 /* admission is not required so access is allowed */
2100 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2101 wmmAcAccessRequired = false;
2102 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2103 wmmAcAccessAllowed = true;
2104 }
2105
2106 }
2107
2108 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2109 "%s: Exiting", __func__);
2110
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302111 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002112}
2113
2114/**
2115 * hdd_wmm_get_uapsd_mask() - Function which will calculate the
2116 * initial value of the UAPSD mask based upon the device configuration
2117 *
2118 * @pAdapter : [in] pointer to adapter context
2119 * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored
2120 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302121 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002122 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302123QDF_STATUS hdd_wmm_get_uapsd_mask(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002124 uint8_t *pUapsdMask)
2125{
2126 uint8_t uapsdMask;
2127
2128 if (HDD_WMM_USER_MODE_NO_QOS ==
2129 (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) {
2130 /* no QOS then no UAPSD */
2131 uapsdMask = 0;
2132 } else {
2133 /* start with the default mask */
2134 uapsdMask = (WLAN_HDD_GET_CTX(pAdapter))->config->UapsdMask;
2135
2136 /* disable UAPSD for any ACs with a 0 Service Interval */
2137 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2138 InfraUapsdVoSrvIntv == 0) {
2139 uapsdMask &= ~HDD_AC_VO;
2140 }
2141
2142 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2143 InfraUapsdViSrvIntv == 0) {
2144 uapsdMask &= ~HDD_AC_VI;
2145 }
2146
2147 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2148 InfraUapsdBkSrvIntv == 0) {
2149 uapsdMask &= ~HDD_AC_BK;
2150 }
2151
2152 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2153 InfraUapsdBeSrvIntv == 0) {
2154 uapsdMask &= ~HDD_AC_BE;
2155 }
2156 }
2157
2158 /* return calculated mask */
2159 *pUapsdMask = uapsdMask;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302160 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002161}
2162
2163/**
2164 * hdd_wmm_is_active() - Function which will determine if WMM is
2165 * active on the current connection
2166 *
2167 * @pAdapter: [in] pointer to adapter context
2168 *
2169 * Return: true if WMM is enabled, false if WMM is not enabled
2170 */
2171bool hdd_wmm_is_active(hdd_adapter_t *pAdapter)
2172{
2173 if ((!pAdapter->hddWmmStatus.wmmQosConnection) ||
2174 (!pAdapter->hddWmmStatus.wmmQap)) {
2175 return false;
2176 } else {
2177 return true;
2178 }
2179}
2180
2181/**
2182 * hdd_wmm_addts() - Function which will add a traffic spec at the
2183 * request of an application
2184 *
2185 * @pAdapter : [in] pointer to adapter context
2186 * @handle : [in] handle to uniquely identify a TS
2187 * @pTspec : [in] pointer to the traffic spec
2188 *
2189 * Return: HDD_WLAN_WMM_STATUS_*
2190 */
2191hdd_wlan_wmm_status_e hdd_wmm_addts(hdd_adapter_t *pAdapter,
2192 uint32_t handle,
2193 sme_QosWmmTspecInfo *pTspec)
2194{
2195 hdd_wmm_qos_context_t *pQosContext;
2196 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2197#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2198 sme_QosStatusType smeStatus;
2199#endif
2200 bool found = false;
2201
2202 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2203 "%s: Entered with handle 0x%x", __func__, handle);
2204
2205 /* see if a context already exists with the given handle */
2206 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2207 list_for_each_entry(pQosContext,
2208 &pAdapter->hddWmmStatus.wmmContextList, node) {
2209 if (pQosContext->handle == handle) {
2210 found = true;
2211 break;
2212 }
2213 }
2214 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2215 if (found) {
2216 /* record with that handle already exists */
2217 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
2218 "%s: Record already exists with handle 0x%x",
2219 __func__, handle);
2220
2221 /* Application is trying to modify some of the Tspec
2222 * params. Allow it
2223 */
2224 smeStatus = sme_qos_modify_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
2225 pTspec, pQosContext->qosFlowId);
2226
2227 /* need to check the return value and act appropriately */
2228 switch (smeStatus) {
2229 case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
2230 status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING;
2231 break;
2232 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2233 status =
2234 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
2235 break;
2236 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
2237 status =
2238 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
2239 break;
2240 case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
2241 status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
2242 break;
2243 case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
2244 status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2245 break;
2246 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2247 status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2248 break;
2249 default:
2250 /* we didn't get back one of the
2251 * SME_QOS_STATUS_MODIFY_* status codes
2252 */
2253 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
2254 "%s: unexpected SME Status=%d", __func__,
2255 smeStatus);
2256 CDF_ASSERT(0);
2257 return HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2258 }
2259
2260 /* we were successful, save the status */
2261 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2262 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2263 pQosContext->lastStatus = status;
2264 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2265
2266 return status;
2267 }
2268
2269 pQosContext = kmalloc(sizeof(*pQosContext), GFP_KERNEL);
2270 if (NULL == pQosContext) {
2271 /* no memory for QoS context. Nothing we can do */
2272 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
2273 "%s: Unable to allocate QoS context", __func__);
2274 return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE;
2275 }
2276 /* we assume the tspec has already been validated by the caller */
2277
2278 pQosContext->handle = handle;
2279 if (pTspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE)
2280 pQosContext->acType = hdd_wmm_up_to_ac_map[pTspec->ts_info.up];
2281 else {
2282 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
2283 "%s: ts_info.up (%d) larger than max value (%d), use default acType (%d)",
2284 __func__, pTspec->ts_info.up,
2285 HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]);
2286 pQosContext->acType = hdd_wmm_up_to_ac_map[0];
2287 }
2288 pQosContext->pAdapter = pAdapter;
2289 pQosContext->qosFlowId = 0;
2290 pQosContext->magic = HDD_WMM_CTX_MAGIC;
2291
2292 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
2293 "%s: Setting up QoS, context %p", __func__, pQosContext);
2294
2295 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2296 list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList);
2297 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2298
2299#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2300 smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
2301 pAdapter->sessionId,
2302 pTspec,
2303 hdd_wmm_sme_callback,
2304 pQosContext,
2305 pTspec->ts_info.up,
2306 &pQosContext->qosFlowId);
2307
2308 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
2309 "%s: sme_qos_setup_req returned %d flowid %d",
2310 __func__, smeStatus, pQosContext->qosFlowId);
2311
2312 /* need to check the return value and act appropriately */
2313 switch (smeStatus) {
2314 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
2315 status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2316 break;
2317 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2318 status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
2319 break;
2320 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
2321 status =
2322 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
2323 break;
2324 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
2325 status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2326 break;
2327 case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
2328 hdd_wmm_free_context(pQosContext);
2329 return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
2330 case SME_QOS_STATUS_SETUP_FAILURE_RSP:
2331 /* we can't tell the difference between when a request
2332 * fails because AP rejected it versus when SME
2333 * encounterd an internal error
2334 */
2335 hdd_wmm_free_context(pQosContext);
2336 return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2337 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2338 hdd_wmm_free_context(pQosContext);
2339 return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2340 default:
2341 /* we didn't get back one of the
2342 * SME_QOS_STATUS_SETUP_* status codes
2343 */
2344 hdd_wmm_free_context(pQosContext);
2345 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
2346 "%s: unexpected SME Status=%d", __func__, smeStatus);
2347 CDF_ASSERT(0);
2348 return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2349 }
2350#endif
2351
2352 /* we were successful, save the status */
2353 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2354 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2355 pQosContext->lastStatus = status;
2356 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2357
2358 return status;
2359}
2360
2361/**
2362 * hdd_wmm_delts() - Function which will delete a traffic spec at the
2363 * request of an application
2364 *
2365 * @pAdapter: [in] pointer to adapter context
2366 * @handle: [in] handle to uniquely identify a TS
2367 *
2368 * Return: HDD_WLAN_WMM_STATUS_*
2369 */
2370hdd_wlan_wmm_status_e hdd_wmm_delts(hdd_adapter_t *pAdapter, uint32_t handle)
2371{
2372 hdd_wmm_qos_context_t *pQosContext;
2373 bool found = false;
2374 sme_ac_enum_type acType = 0;
2375 uint32_t qosFlowId = 0;
2376 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2377#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2378 sme_QosStatusType smeStatus;
2379#endif
2380
2381 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2382 "%s: Entered with handle 0x%x", __func__, handle);
2383
2384 /* locate the context with the given handle */
2385 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2386 list_for_each_entry(pQosContext,
2387 &pAdapter->hddWmmStatus.wmmContextList, node) {
2388 if (pQosContext->handle == handle) {
2389 found = true;
2390 acType = pQosContext->acType;
2391 qosFlowId = pQosContext->qosFlowId;
2392 break;
2393 }
2394 }
2395 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2396
2397 if (false == found) {
2398 /* we didn't find the handle */
2399 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2400 "%s: handle 0x%x not found", __func__, handle);
2401 return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2402 }
2403
2404 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2405 "%s: found handle 0x%x, flow %d, AC %d, context %p",
2406 __func__, handle, qosFlowId, acType, pQosContext);
2407
2408#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2409 smeStatus =
2410 sme_qos_release_req(WLAN_HDD_GET_HAL_CTX(pAdapter), qosFlowId);
2411
2412 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2413 "%s: SME flow %d released, SME status %d",
2414 __func__, qosFlowId, smeStatus);
2415
2416 switch (smeStatus) {
2417 case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
2418 /* this flow is the only one on that AC, so go ahead
2419 * and update our TSPEC state for the AC
2420 */
2421 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcTspecValid =
2422 false;
2423
2424 /* need to tell TL to stop trigger timer, etc */
2425 hdd_wmm_disable_tl_uapsd(pQosContext);
2426
2427#ifdef FEATURE_WLAN_ESE
2428 /* disable the inactivity timer */
2429 hdd_wmm_disable_inactivity_timer(pQosContext);
2430#endif
2431 /* we are done with this context */
2432 hdd_wmm_free_context(pQosContext);
2433
2434 /* SME must not fire any more callbacks for this flow
2435 * since the context is no longer valid
2436 */
2437
2438 return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
2439
2440 case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
2441 /* do nothing as we will get a response from SME */
2442 status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING;
2443 break;
2444
2445 case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
2446 /* nothing we can do with the existing flow except leave it */
2447 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2448 break;
2449
2450 case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
2451 /* nothing we can do with the existing flow except leave it */
2452 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2453
2454 default:
2455 /* we didn't get back one of the
2456 * SME_QOS_STATUS_RELEASE_* status codes
2457 */
2458 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
2459 "%s: unexpected SME Status=%d", __func__, smeStatus);
2460 CDF_ASSERT(0);
2461 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2462 }
2463
2464#endif
2465 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2466 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2467 pQosContext->lastStatus = status;
2468 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2469
2470 return status;
2471}
2472
2473/**
2474 * hdd_wmm_checkts() - Function which will return the status of a traffic
2475 * spec at the request of an application
2476 *
2477 * @pAdapter: [in] pointer to adapter context
2478 * @handle: [in] handle to uniquely identify a TS
2479 *
2480 * Return: HDD_WLAN_WMM_STATUS_*
2481 */
2482hdd_wlan_wmm_status_e hdd_wmm_checkts(hdd_adapter_t *pAdapter, uint32_t handle)
2483{
2484 hdd_wmm_qos_context_t *pQosContext;
2485 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST;
2486
2487 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2488 "%s: Entered with handle 0x%x", __func__, handle);
2489
2490 /* locate the context with the given handle */
2491 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2492 list_for_each_entry(pQosContext,
2493 &pAdapter->hddWmmStatus.wmmContextList, node) {
2494 if (pQosContext->handle == handle) {
2495 CDF_TRACE(CDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
2496 "%s: found handle 0x%x, context %p",
2497 __func__, handle, pQosContext);
2498
2499 status = pQosContext->lastStatus;
2500 break;
2501 }
2502 }
2503 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2504 return status;
2505}