blob: 7ecbb79b099505f44c454e4cc16a63a9ea6da5ff [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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +053067#define WMM_TRACE_LEVEL_FATAL QDF_TRACE_LEVEL_FATAL
68#define WMM_TRACE_LEVEL_ERROR QDF_TRACE_LEVEL_FATAL
69#define WMM_TRACE_LEVEL_WARN QDF_TRACE_LEVEL_FATAL
70#define WMM_TRACE_LEVEL_INFO QDF_TRACE_LEVEL_FATAL
71#define WMM_TRACE_LEVEL_INFO_HIGH QDF_TRACE_LEVEL_FATAL
72#define WMM_TRACE_LEVEL_INFO_LOW QDF_TRACE_LEVEL_FATAL
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080073#else
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +053074#define WMM_TRACE_LEVEL_FATAL QDF_TRACE_LEVEL_FATAL
75#define WMM_TRACE_LEVEL_ERROR QDF_TRACE_LEVEL_ERROR
76#define WMM_TRACE_LEVEL_WARN QDF_TRACE_LEVEL_WARN
77#define WMM_TRACE_LEVEL_INFO QDF_TRACE_LEVEL_INFO
78#define WMM_TRACE_LEVEL_INFO_HIGH QDF_TRACE_LEVEL_INFO_HIGH
79#define WMM_TRACE_LEVEL_INFO_LOW QDF_TRACE_LEVEL_INFO_LOW
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080080#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) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530169 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800170 "%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 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530181 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800182 "%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)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530197 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800198 "%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)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530213 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800214 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530225 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800226 "%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)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530258 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Sreelakshmi Konamkie1ce5622015-11-23 15:04:05 +0530259 "%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;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530264 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Sreelakshmi Konamkie1ce5622015-11-23 15:04:05 +0530265 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530284 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800285 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530328 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800329 "%s: Entered, context %p", __func__, pQosContext);
330
331 if (unlikely((NULL == pQosContext) ||
332 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530333 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800334 "%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 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530353 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800354 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530391 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800392 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);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530399 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800400 FL(
401 "Deleted TS on AC %d, due to inactivity with status = %d!!!"
402 ),
403 acType, status);
404 } else {
405 pAc->wmmPrevTrafficCnt = currentTrafficCnt;
Anurag Chouhan210db072016-02-22 18:42:15 +0530406 if (pAc->wmmInactivityTimer.state == QDF_TIMER_STATE_STOPPED) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800407 /* Restart the timer */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530408 qdf_status =
Anurag Chouhan210db072016-02-22 18:42:15 +0530409 qdf_mc_timer_start(&pAc->wmmInactivityTimer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800410 pAc->wmmInactivityTime);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530411 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530412 QDF_TRACE(QDF_MODULE_ID_HDD,
413 QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800414 FL(
415 "Restarting inactivity timer failed on AC %d"
416 ),
417 acType);
418 }
419 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530420 QDF_ASSERT(qdf_mc_timer_get_current_state
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800421 (&pAc->wmmInactivityTimer) ==
Anurag Chouhan210db072016-02-22 18:42:15 +0530422 QDF_TIMER_STATE_STOPPED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 }
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 Chouhan210db072016-02-22 18:42:15 +0530454 qdf_status = qdf_mc_timer_init(&pAc->wmmInactivityTimer,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530455 QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800456 hdd_wmm_inactivity_timer_cb,
457 pQosContext);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530458 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530459 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800460 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 Chouhan210db072016-02-22 18:42:15 +0530465 qdf_status = qdf_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)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530468 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800469 FL("Starting inactivity timer failed on AC %d"),
470 acType);
Anurag Chouhan210db072016-02-22 18:42:15 +0530471 qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530472 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 Chouhan210db072016-02-22 18:42:15 +0530511 qdf_status = qdf_mc_timer_stop(&pAc->wmmInactivityTimer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530512 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 Chouhan210db072016-02-22 18:42:15 +0530516 qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530517 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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530552 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800553 "%s: Entered, context %p", __func__, pQosContext);
554
555 if (unlikely((NULL == pQosContext) ||
556 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530557 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800558 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530566 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800567 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530573 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800574 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530591 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800592 "%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) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530604 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800605 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530620 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800621 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530630 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800631 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530643 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800644 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530652 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800653 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530675 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800676 "%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 {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530692 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800693 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530704 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800705 "%s: Setup failed, not a QoS AP", __func__);
706 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530707 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800708 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530719 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800720 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530725 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800726 "%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) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530734 QDF_TRACE(QDF_MODULE_ID_HDD,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800735 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 {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530760 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530776 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800777 "%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 {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530792 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530810 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800811 "%s: Release is complete", __func__);
812
813 if (pCurrentQosInfo) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530814 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800815 "%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 {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530826 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800827 "%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) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530842 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800843 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530856 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800857 "%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) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530863 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800864 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530876 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800877 "%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 {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530892 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800893 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530906 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800907 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530912 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800913 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530923 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800924 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530969 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800970 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301002 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001003 "%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:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301038 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001039 "%s: unexpected SME Status=%d", __func__, smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301040 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001041 }
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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301058 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001059 "%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) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301077 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001078 "%s: pAdapter is NULL", __func__);
1079 return -EINVAL;
1080 }
1081 if (NULL == ptr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301082 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001083 "%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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301113 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001114 "%s: Entered, context %p", __func__, pQosContext);
1115
1116 if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301117 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001118 "%s: Invalid QoS Context", __func__);
1119 return;
1120 }
1121
1122 pAdapter = pQosContext->pAdapter;
1123
1124 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301125 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001126 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001127
1128 acType = pQosContext->acType;
1129 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1130
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301131 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001132 "%s: pAdapter %p acType %d", __func__, pAdapter, acType);
1133
1134 if (!pAc->wmmAcAccessNeeded) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301135 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001136 "%s: AC %d doesn't need service", __func__, acType);
1137 pQosContext->magic = 0;
1138 kfree(pQosContext);
1139 return;
1140 }
1141
1142 pAc->wmmAcAccessPending = true;
1143 pAc->wmmAcAccessNeeded = false;
1144
1145 memset(&qosInfo, 0, sizeof(qosInfo));
1146
1147 qosInfo.ts_info.psb = pAdapter->configuredPsb;
1148
1149 switch (acType) {
1150 case SME_AC_VO:
1151 qosInfo.ts_info.up = SME_QOS_WMM_UP_VO;
1152 /* Check if there is any valid configuration from framework */
1153 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1154 qosInfo.ts_info.psb =
1155 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1156 UapsdMask & SME_QOS_UAPSD_VO) ? 1 : 0;
1157 }
1158 qosInfo.ts_info.direction =
1159 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVo;
1160 qosInfo.ts_info.tid = 255;
1161 qosInfo.mean_data_rate =
1162 (WLAN_HDD_GET_CTX(pAdapter))->config->
1163 InfraMeanDataRateAcVo;
1164 qosInfo.min_phy_rate =
1165 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVo;
1166 qosInfo.min_service_interval =
1167 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSrvIntv;
1168 qosInfo.nominal_msdu_size =
1169 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVo;
1170 qosInfo.surplus_bw_allowance =
1171 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVo;
1172 qosInfo.suspension_interval =
1173 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSuspIntv;
1174 break;
1175 case SME_AC_VI:
1176 qosInfo.ts_info.up = SME_QOS_WMM_UP_VI;
1177 /* Check if there is any valid configuration from framework */
1178 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1179 qosInfo.ts_info.psb =
1180 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1181 UapsdMask & SME_QOS_UAPSD_VI) ? 1 : 0;
1182 }
1183 qosInfo.ts_info.direction =
1184 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVi;
1185 qosInfo.ts_info.tid = 255;
1186 qosInfo.mean_data_rate =
1187 (WLAN_HDD_GET_CTX(pAdapter))->config->
1188 InfraMeanDataRateAcVi;
1189 qosInfo.min_phy_rate =
1190 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVi;
1191 qosInfo.min_service_interval =
1192 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSrvIntv;
1193 qosInfo.nominal_msdu_size =
1194 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVi;
1195 qosInfo.surplus_bw_allowance =
1196 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVi;
1197 qosInfo.suspension_interval =
1198 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSuspIntv;
1199 break;
1200 default:
1201 case SME_AC_BE:
1202 qosInfo.ts_info.up = SME_QOS_WMM_UP_BE;
1203 /* Check if there is any valid configuration from framework */
1204 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1205 qosInfo.ts_info.psb =
1206 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1207 UapsdMask & SME_QOS_UAPSD_BE) ? 1 : 0;
1208 }
1209 qosInfo.ts_info.direction =
1210 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBe;
1211 qosInfo.ts_info.tid = 255;
1212 qosInfo.mean_data_rate =
1213 (WLAN_HDD_GET_CTX(pAdapter))->config->
1214 InfraMeanDataRateAcBe;
1215 qosInfo.min_phy_rate =
1216 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBe;
1217 qosInfo.min_service_interval =
1218 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSrvIntv;
1219 qosInfo.nominal_msdu_size =
1220 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBe;
1221 qosInfo.surplus_bw_allowance =
1222 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBe;
1223 qosInfo.suspension_interval =
1224 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSuspIntv;
1225 break;
1226 case SME_AC_BK:
1227 qosInfo.ts_info.up = SME_QOS_WMM_UP_BK;
1228 /* Check if there is any valid configuration from framework */
1229 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1230 qosInfo.ts_info.psb =
1231 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1232 UapsdMask & SME_QOS_UAPSD_BK) ? 1 : 0;
1233 }
1234 qosInfo.ts_info.direction =
1235 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBk;
1236 qosInfo.ts_info.tid = 255;
1237 qosInfo.mean_data_rate =
1238 (WLAN_HDD_GET_CTX(pAdapter))->config->
1239 InfraMeanDataRateAcBk;
1240 qosInfo.min_phy_rate =
1241 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBk;
1242 qosInfo.min_service_interval =
1243 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSrvIntv;
1244 qosInfo.nominal_msdu_size =
1245 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBk;
1246 qosInfo.surplus_bw_allowance =
1247 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBk;
1248 qosInfo.suspension_interval =
1249 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSuspIntv;
1250 break;
1251 }
1252#ifdef FEATURE_WLAN_ESE
1253 qosInfo.inactivity_interval =
1254 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraInactivityInterval;
1255#endif
1256 qosInfo.ts_info.burst_size_defn =
1257 (WLAN_HDD_GET_CTX(pAdapter))->config->burstSizeDefinition;
1258
1259 switch ((WLAN_HDD_GET_CTX(pAdapter))->config->tsInfoAckPolicy) {
1260 case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK:
1261 qosInfo.ts_info.ack_policy =
1262 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1263 break;
1264
1265 case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK:
1266 qosInfo.ts_info.ack_policy =
1267 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK;
1268 break;
1269
1270 default:
1271 /* unknown */
1272 qosInfo.ts_info.ack_policy =
1273 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1274 }
1275
1276 if (qosInfo.ts_info.ack_policy ==
1277 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) {
1278 if (!sme_qos_is_ts_info_ack_policy_valid
1279 ((tpAniSirGlobal) WLAN_HDD_GET_HAL_CTX(pAdapter), &qosInfo,
1280 pAdapter->sessionId)) {
1281 qosInfo.ts_info.ack_policy =
1282 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1283 }
1284 }
1285
1286 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
1287 list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList);
1288 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
1289
1290#ifndef WLAN_MDM_CODE_REDUCTION_OPT
1291 smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
1292 pAdapter->sessionId,
1293 &qosInfo,
1294 hdd_wmm_sme_callback,
1295 pQosContext,
1296 qosInfo.ts_info.up,
1297 &pQosContext->qosFlowId);
1298
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301299 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001300 "%s: sme_qos_setup_req returned %d flowid %d",
1301 __func__, smeStatus, pQosContext->qosFlowId);
1302
1303 /* need to check the return values and act appropriately */
1304 switch (smeStatus) {
1305 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
1306 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
1307 /* setup is pending, so no more work to do now. all
1308 * further work will be done in hdd_wmm_sme_callback()
1309 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301310 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001311 "%s: Setup is pending, no further work", __func__);
1312
1313 break;
1314
1315 case SME_QOS_STATUS_SETUP_FAILURE_RSP:
1316 /* we can't tell the difference between when a request
1317 * fails because AP rejected it versus when SME
1318 * encountered an internal error. in either case SME
1319 * won't ever reference this context so free the
1320 * record
1321 */
1322 hdd_wmm_free_context(pQosContext);
1323
1324 /* fall through and start packets flowing */
1325 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
1326 /* no ACM in effect, no need to setup U-APSD */
1327 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
1328 /* no ACM in effect, U-APSD is desired but was already setup */
1329
1330 /* for these cases everything is already setup so we
1331 * can signal TL that it has work to do
1332 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301333 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001334 "%s: Setup is complete, notify TL", __func__);
1335
1336 pAc->wmmAcAccessAllowed = true;
1337 pAc->wmmAcAccessGranted = true;
1338 pAc->wmmAcAccessPending = false;
1339
1340 break;
1341
1342 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301343 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001344 "%s: unexpected SME Status=%d", __func__, smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301345 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001346 }
1347#endif
1348
1349}
1350
1351/**
1352 * hdd_wmm_do_implicit_qos() - SSR wraper function for hdd_wmm_do_implicit_qos
1353 * @work: pointer to work_struct
1354 *
1355 * Return: none
1356 */
1357static void hdd_wmm_do_implicit_qos(struct work_struct *work)
1358{
1359 cds_ssr_protect(__func__);
1360 __hdd_wmm_do_implicit_qos(work);
1361 cds_ssr_unprotect(__func__);
1362}
1363
1364/**
1365 * hdd_wmm_init() - initialize the WMM DSCP configuation
1366 * @pAdapter : [in] pointer to Adapter context
1367 *
1368 * This function will initialize the WMM DSCP configuation of an
1369 * adapter to an initial state. The configuration can later be
1370 * overwritten via application APIs or via QoS Map sent OTA.
1371 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301372 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001373 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301374QDF_STATUS hdd_wmm_init(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001375{
1376 sme_QosWmmUpType *hddWmmDscpToUpMap = pAdapter->hddWmmDscpToUpMap;
1377 uint8_t dscp;
1378
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301379 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001380 "%s: Entered", __func__);
1381
1382 /* DSCP to User Priority Lookup Table
1383 * By default use the 3 Precedence bits of DSCP as the User Priority
1384 */
1385 for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++) {
1386 hddWmmDscpToUpMap[dscp] = dscp >> 3;
1387 }
1388
1389 /* Special case for Expedited Forwarding (DSCP 46) */
1390 hddWmmDscpToUpMap[46] = SME_QOS_WMM_UP_VO;
1391
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301392 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001393}
1394
1395/**
1396 * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter
1397 * @pAdapter: [in] pointer to Adapter context
1398 *
1399 * This function will initialize the WMM configuation and status of an
1400 * adapter to an initial state. The configuration can later be
1401 * overwritten via application APIs
1402 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301403 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001404 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301405QDF_STATUS hdd_wmm_adapter_init(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001406{
1407 hdd_wmm_ac_status_t *pAcStatus;
1408 sme_ac_enum_type acType;
1409
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301410 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411 "%s: Entered", __func__);
1412
1413 pAdapter->hddWmmStatus.wmmQap = false;
1414 INIT_LIST_HEAD(&pAdapter->hddWmmStatus.wmmContextList);
1415 mutex_init(&pAdapter->hddWmmStatus.wmmLock);
1416
1417 for (acType = 0; acType < WLAN_MAX_AC; acType++) {
1418 pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1419 pAcStatus->wmmAcAccessRequired = false;
1420 pAcStatus->wmmAcAccessNeeded = false;
1421 pAcStatus->wmmAcAccessPending = false;
1422 pAcStatus->wmmAcAccessFailed = false;
1423 pAcStatus->wmmAcAccessGranted = false;
1424 pAcStatus->wmmAcAccessAllowed = false;
1425 pAcStatus->wmmAcTspecValid = false;
1426 pAcStatus->wmmAcUapsdInfoValid = false;
1427 }
1428 /* Invalid value(0xff) to indicate psb not configured through
1429 * framework initially.
1430 */
1431 pAdapter->configuredPsb = HDD_PSB_CFG_INVALID;
1432
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301433 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001434}
1435
1436/**
1437 * hdd_wmm_adapter_clear() - Function which will clear the WMM status
1438 * for all the ACs
1439 *
1440 * @pAdapter: [in] pointer to Adapter context
1441 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301442 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001443 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301444QDF_STATUS hdd_wmm_adapter_clear(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445{
1446 hdd_wmm_ac_status_t *pAcStatus;
1447 sme_ac_enum_type acType;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301448 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449 "%s: Entered", __func__);
1450 for (acType = 0; acType < WLAN_MAX_AC; acType++) {
1451 pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1452 pAcStatus->wmmAcAccessRequired = false;
1453 pAcStatus->wmmAcAccessNeeded = false;
1454 pAcStatus->wmmAcAccessPending = false;
1455 pAcStatus->wmmAcAccessFailed = false;
1456 pAcStatus->wmmAcAccessGranted = false;
1457 pAcStatus->wmmAcAccessAllowed = false;
1458 pAcStatus->wmmAcTspecValid = false;
1459 pAcStatus->wmmAcUapsdInfoValid = false;
1460 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301461 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001462}
1463
1464/**
1465 * hdd_wmm_close() - WMM close function
1466 * @pAdapter: [in] pointer to adapter context
1467 *
1468 * Function which will perform any necessary work to to clean up the
1469 * WMM functionality prior to the kernel module unload.
1470 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301471 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001472 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301473QDF_STATUS hdd_wmm_adapter_close(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474{
1475 hdd_wmm_qos_context_t *pQosContext;
1476
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301477 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001478 "%s: Entered", __func__);
1479
1480 /* free any context records that we still have linked */
1481 while (!list_empty(&pAdapter->hddWmmStatus.wmmContextList)) {
1482 pQosContext =
1483 list_first_entry(&pAdapter->hddWmmStatus.wmmContextList,
1484 hdd_wmm_qos_context_t, node);
1485#ifdef FEATURE_WLAN_ESE
1486 hdd_wmm_disable_inactivity_timer(pQosContext);
1487#endif
1488 if (pQosContext->handle == HDD_WMM_HANDLE_IMPLICIT
1489 && pQosContext->magic == HDD_WMM_CTX_MAGIC)
1490 cds_flush_work(&pQosContext->wmmAcSetupImplicitQos);
1491
1492 hdd_wmm_free_context(pQosContext);
1493 }
1494
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301495 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001496}
1497
1498/**
1499 * hdd_wmm_classify_pkt() - Function which will classify an OS packet
Govind Singhb7ab5772015-10-08 16:38:37 +05301500 * into a WMM AC based on DSCP
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001501 *
Govind Singhb7ab5772015-10-08 16:38:37 +05301502 * @adapter: adapter upon which the packet is being transmitted
1503 * @skb: pointer to network buffer
1504 * @user_pri: user priority of the OS packet
1505 * @is_eapol: eapol packet flag
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001506 *
1507 * Return: None
1508 */
1509static
Govind Singhb7ab5772015-10-08 16:38:37 +05301510void hdd_wmm_classify_pkt(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001511 struct sk_buff *skb,
Govind Singhb7ab5772015-10-08 16:38:37 +05301512 sme_QosWmmUpType *user_pri,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513 bool *is_eapol)
1514{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001515 unsigned char dscp;
Govind Singhb7ab5772015-10-08 16:38:37 +05301516 unsigned char tos;
1517 union generic_ethhdr *eth_hdr;
1518 struct iphdr *ip_hdr;
1519 struct ipv6hdr *ipv6hdr;
1520 unsigned char *pkt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521
1522 /* this code is executed for every packet therefore
1523 * all debug code is kept conditional
1524 */
1525
1526#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301527 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001528 "%s: Entered", __func__);
1529#endif /* HDD_WMM_DEBUG */
1530
Govind Singhb7ab5772015-10-08 16:38:37 +05301531 pkt = skb->data;
1532 eth_hdr = (union generic_ethhdr *)pkt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001533
1534#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301535 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Govind Singhb7ab5772015-10-08 16:38:37 +05301536 "%s: proto is 0x%04x", __func__, skb->protocol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001537#endif /* HDD_WMM_DEBUG */
1538
Govind Singhb7ab5772015-10-08 16:38:37 +05301539 if (eth_hdr->eth_II.h_proto == htons(ETH_P_IP)) {
1540 /* case 1: Ethernet II IP packet */
1541 ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_II)];
1542 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001543#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301544 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Govind Singhb7ab5772015-10-08 16:38:37 +05301545 "%s: Ethernet II IP Packet, tos is %d",
1546 __func__, tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001547#endif /* HDD_WMM_DEBUG */
1548
Govind Singhb7ab5772015-10-08 16:38:37 +05301549 } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) {
1550 ipv6hdr = ipv6_hdr(skb);
1551 tos = ntohs(*(const __be16 *)ipv6hdr) >> 4;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001552#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301553 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Govind Singhb7ab5772015-10-08 16:38:37 +05301554 "%s: Ethernet II IPv6 Packet, tos is %d",
1555 __func__, tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001556#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301557 } else if ((ntohs(eth_hdr->eth_II.h_proto) < WLAN_MIN_PROTO) &&
1558 (eth_hdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) &&
1559 (eth_hdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) &&
1560 (eth_hdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) &&
1561 (eth_hdr->eth_8023.h_proto == htons(ETH_P_IP))) {
1562 /* case 2: 802.3 LLC/SNAP IP packet */
1563 ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_8023)];
1564 tos = ip_hdr->tos;
1565#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301566 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Govind Singhb7ab5772015-10-08 16:38:37 +05301567 "%s: 802.3 LLC/SNAP IP Packet, tos is %d",
1568 __func__, tos);
1569#endif /* HDD_WMM_DEBUG */
1570 } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) {
1571 /* VLAN tagged */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001572
Govind Singhb7ab5772015-10-08 16:38:37 +05301573 if (eth_hdr->eth_IIv.h_vlan_encapsulated_proto ==
1574 htons(ETH_P_IP)) {
1575 /* case 3: Ethernet II vlan-tagged IP packet */
1576 ip_hdr =
1577 (struct iphdr *)
1578 &pkt[sizeof(eth_hdr->eth_IIv)];
1579 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001580#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301581 QDF_TRACE(QDF_MODULE_ID_HDD,
Govind Singhb7ab5772015-10-08 16:38:37 +05301582 WMM_TRACE_LEVEL_INFO_LOW,
1583 "%s: Ethernet II VLAN tagged IP Packet, tos is %d",
1584 __func__, tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001585#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301586 } else
1587 if ((ntohs(eth_hdr->eth_IIv.h_vlan_encapsulated_proto)
1588 < WLAN_MIN_PROTO)
1589 && (eth_hdr->eth_8023v.h_snap.dsap ==
1590 WLAN_SNAP_DSAP)
1591 && (eth_hdr->eth_8023v.h_snap.ssap ==
1592 WLAN_SNAP_SSAP)
1593 && (eth_hdr->eth_8023v.h_snap.ctrl ==
1594 WLAN_SNAP_CTRL)
1595 && (eth_hdr->eth_8023v.h_proto ==
1596 htons(ETH_P_IP))) {
1597 /* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */
1598 ip_hdr =
1599 (struct iphdr *)
1600 &pkt[sizeof(eth_hdr->eth_8023v)];
1601 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001602#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301603 QDF_TRACE(QDF_MODULE_ID_HDD,
Govind Singhb7ab5772015-10-08 16:38:37 +05301604 WMM_TRACE_LEVEL_INFO_LOW,
1605 "%s: 802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d",
1606 __func__, tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001607#endif /* HDD_WMM_DEBUG */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001608 } else {
1609 /* default */
1610#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301611 QDF_TRACE(QDF_MODULE_ID_HDD,
Govind Singhb7ab5772015-10-08 16:38:37 +05301612 WMM_TRACE_LEVEL_WARN,
1613 "%s: VLAN tagged Unhandled Protocol, using default tos",
1614 __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301616 tos = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617 }
1618 } else {
1619 /* default */
1620#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301621 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_WARN,
Govind Singhb7ab5772015-10-08 16:38:37 +05301622 "%s: Unhandled Protocol, using default tos",
1623 __func__);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001624#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301625 /* Give the highest priority to 802.1x packet */
1626 if (eth_hdr->eth_II.h_proto ==
1627 htons(HDD_ETHERTYPE_802_1_X)) {
1628 tos = 0xC0;
1629 *is_eapol = true;
1630 } else
1631 tos = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632 }
1633
Govind Singhb7ab5772015-10-08 16:38:37 +05301634 dscp = (tos >> 2) & 0x3f;
1635 *user_pri = adapter->hddWmmDscpToUpMap[dscp];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001636
1637#ifdef HDD_WMM_DEBUG
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301638 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Govind Singhb7ab5772015-10-08 16:38:37 +05301639 "%s: tos is %d, dscp is %d, up is %d",
1640 __func__, tos, dscp, *user_pri);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641#endif /* HDD_WMM_DEBUG */
1642
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001643 return;
1644}
1645
1646#ifdef QCA_LL_TX_FLOW_CONTROL_V2
1647/**
1648 * hdd_get_queue_index() - get queue index
1649 * @up: user priority
1650 * @is_eapol: is_eapol flag
1651 *
1652 * Return: queue_index
1653 */
1654static
1655uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol)
1656{
Anurag Chouhanc5548422016-02-24 18:33:27 +05301657 if (qdf_unlikely(is_eapol == true))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001658 return HDD_LINUX_AC_HI_PRIO;
1659 else
1660 return hdd_linux_up_to_ac_map[up];
1661}
1662#else
1663static
1664uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol)
1665{
1666 return hdd_linux_up_to_ac_map[up];
1667}
1668#endif
1669
1670
1671/**
1672 * hdd_hostapd_select_queue() - Function which will classify the packet
1673 * according to linux qdisc expectation.
1674 *
1675 * @dev: [in] pointer to net_device structure
1676 * @skb: [in] pointer to os packet
1677 *
1678 * Return: Qdisc queue index
1679 */
1680uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb
1681#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
1682 , void *accel_priv
1683#endif
1684#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1685 , select_queue_fallback_t fallback
1686#endif
1687
1688)
1689{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001690 sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
1691 uint16_t queueIndex;
Govind Singhb7ab5772015-10-08 16:38:37 +05301692 hdd_adapter_t *adapter = (hdd_adapter_t *) netdev_priv(dev);
1693 hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001694 bool is_eapol = false;
Mukul Sharmab3152182015-10-30 20:47:30 +05301695 int status = 0;
Govind Singhb7ab5772015-10-08 16:38:37 +05301696 status = wlan_hdd_validate_context(hddctx);
Mukul Sharmab3152182015-10-30 20:47:30 +05301697
1698 if (status != 0) {
1699 skb->priority = SME_QOS_WMM_UP_BE;
1700 return HDD_LINUX_AC_BE;
1701 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702
Govind Singhb7ab5772015-10-08 16:38:37 +05301703 /* Get the user priority from IP header */
1704 hdd_wmm_classify_pkt(adapter, skb, &up, &is_eapol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001705 skb->priority = up;
1706 queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
1707
1708 return queueIndex;
1709}
1710
1711/**
1712 * hdd_wmm_select_queue() - Function which will classify the packet
1713 * according to linux qdisc expectation.
1714 *
1715 * @dev: [in] pointer to net_device structure
1716 * @skb: [in] pointer to os packet
1717 *
1718 * Return: Qdisc queue index
1719 */
1720uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb)
1721{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001722 sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
1723 uint16_t queueIndex;
1724 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1725 bool is_eapol = false;
Mukul Sharmabfd19ba2015-10-30 20:35:35 +05301726 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
1727 int status;
1728
1729 status = wlan_hdd_validate_context(hdd_ctx);
1730 if (status != 0) {
1731 skb->priority = SME_QOS_WMM_UP_BE;
1732 return HDD_LINUX_AC_BE;
1733 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001734
Govind Singhb7ab5772015-10-08 16:38:37 +05301735 /* Get the user priority from IP header */
1736 hdd_wmm_classify_pkt(pAdapter, skb, &up, &is_eapol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001737 skb->priority = up;
1738 queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
Govind Singhb7ab5772015-10-08 16:38:37 +05301739
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001740 return queueIndex;
1741}
1742
1743/**
1744 * hdd_wmm_acquire_access_required() - Function which will determine
1745 * acquire admittance for a WMM AC is required or not based on psb configuration
1746 * done in framework
1747 *
1748 * @pAdapter: [in] pointer to adapter structure
1749 * @acType: [in] WMM AC type of OS packet
1750 *
1751 * Return: void
1752 */
1753void hdd_wmm_acquire_access_required(hdd_adapter_t *pAdapter,
1754 sme_ac_enum_type acType)
1755{
1756 /* Each bit in the LSB nibble indicates 1 AC.
1757 * Clearing the particular bit in LSB nibble to indicate
1758 * access required
1759 */
1760 switch (acType) {
1761 case SME_AC_BK:
1762 /* clear first bit */
1763 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK;
1764 break;
1765 case SME_AC_BE:
1766 /* clear second bit */
1767 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK;
1768 break;
1769 case SME_AC_VI:
1770 /* clear third bit */
1771 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK;
1772 break;
1773 case SME_AC_VO:
1774 /* clear fourth bit */
1775 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK;
1776 break;
1777 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301778 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001779 "%s: Invalid AC Type", __func__);
1780 break;
1781 }
1782}
1783
1784/**
1785 * hdd_wmm_acquire_access() - Function which will attempt to acquire
1786 * admittance for a WMM AC
1787 *
1788 * @pAdapter: [in] pointer to adapter context
1789 * @acType: [in] WMM AC type of OS packet
1790 * @pGranted: [out] pointer to bool flag when indicates if access
1791 * has been granted or not
1792 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301793 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301795QDF_STATUS hdd_wmm_acquire_access(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001796 sme_ac_enum_type acType, bool *pGranted)
1797{
1798 hdd_wmm_qos_context_t *pQosContext;
1799
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001800 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001801 "%s: Entered for AC %d", __func__, acType);
1802
1803 if (!hdd_wmm_is_active(pAdapter) ||
1804 !(WLAN_HDD_GET_CTX(pAdapter))->config->bImplicitQosEnabled ||
1805 !pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessRequired) {
1806 /* either we don't want QoS or the AP doesn't support
1807 * QoS or we don't want to do implicit QoS
1808 */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001809 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001810 "%s: QoS not configured on both ends ", __func__);
1811
1812 *pGranted =
1813 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1814 wmmAcAccessAllowed;
1815
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301816 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817 }
1818 /* do we already have an implicit QoS request pending for this AC? */
1819 if ((pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded) ||
1820 (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessPending)) {
1821 /* request already pending so we need to wait for that
1822 * response
1823 */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001824 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825 "%s: Implicit QoS for TL AC %d already scheduled",
1826 __func__, acType);
1827
1828 *pGranted = false;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301829 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001830 }
1831 /* did we already fail to establish implicit QoS for this AC?
1832 * (if so, access should have been granted when the failure
1833 * was handled)
1834 */
1835 if (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessFailed) {
1836 /* request previously failed
1837 * allow access, but we'll be downgraded
1838 */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001839 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001840 "%s: Implicit QoS for TL AC %d previously failed",
1841 __func__, acType);
1842
1843 if (!pAdapter->hddWmmStatus.wmmAcStatus[acType].
1844 wmmAcAccessRequired) {
1845 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1846 wmmAcAccessAllowed = true;
1847 *pGranted = true;
1848 } else {
1849 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1850 wmmAcAccessAllowed = false;
1851 *pGranted = false;
1852 }
1853
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301854 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001855 }
1856 /* we need to establish implicit QoS */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001857 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001858 "%s: Need to schedule implicit QoS for TL AC %d, pAdapter is %p",
1859 __func__, acType, pAdapter);
1860
1861 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded = true;
1862
1863 pQosContext = kmalloc(sizeof(*pQosContext), GFP_ATOMIC);
1864 if (NULL == pQosContext) {
1865 /* no memory for QoS context. Nothing we can do but
1866 * let data flow
1867 */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001868 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001869 "%s: Unable to allocate context", __func__);
1870 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed =
1871 true;
1872 *pGranted = true;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301873 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001874 }
1875
1876 pQosContext->acType = acType;
1877 pQosContext->pAdapter = pAdapter;
1878 pQosContext->qosFlowId = 0;
1879 pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT;
1880 pQosContext->magic = HDD_WMM_CTX_MAGIC;
1881 pQosContext->is_inactivity_timer_running = false;
1882
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001883 INIT_WORK(&pQosContext->wmmAcSetupImplicitQos, hdd_wmm_do_implicit_qos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001884
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001885 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001886 "%s: Scheduling work for AC %d, context %p",
1887 __func__, acType, pQosContext);
1888
1889 schedule_work(&pQosContext->wmmAcSetupImplicitQos);
1890
1891 /* caller will need to wait until the work takes place and
1892 * TSPEC negotiation completes
1893 */
1894 *pGranted = false;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301895 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001896}
1897
1898/**
1899 * hdd_wmm_assoc() - Function which will handle the housekeeping
1900 * required by WMM when association takes place
1901 *
1902 * @pAdapter: [in] pointer to adapter context
1903 * @pRoamInfo: [in] pointer to roam information
1904 * @eBssType: [in] type of BSS
1905 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301906 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301908QDF_STATUS hdd_wmm_assoc(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001909 tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType)
1910{
1911 uint8_t uapsdMask;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301912 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001913 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1914
1915 /* when we associate we need to notify TL if it needs to
1916 * enable UAPSD for any access categories
1917 */
1918
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301919 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001920 "%s: Entered", __func__);
1921
1922 if (pRoamInfo->fReassocReq) {
1923 /* when we reassociate we should continue to use
1924 * whatever parameters were previously established.
1925 * if we are reassociating due to a U-APSD change for
1926 * a particular Access Category, then the change will
1927 * be communicated to HDD via the QoS callback
1928 * associated with the given flow, and U-APSD
1929 * parameters will be updated there
1930 */
1931
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301932 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001933 "%s: Reassoc so no work, Exiting", __func__);
1934
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301935 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936 }
1937 /* get the negotiated UAPSD Mask */
1938 uapsdMask =
1939 pRoamInfo->u.pConnectedProfile->modifyProfileFields.uapsd_mask;
1940
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301941 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001942 "%s: U-APSD mask is 0x%02x", __func__, (int)uapsdMask);
1943
1944 if (uapsdMask & HDD_AC_VO) {
1945 status =
1946 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1947 pcds_context,
1948 (WLAN_HDD_GET_STATION_CTX_PTR
1949 (pAdapter))->conn_info.staId[0],
1950 SME_AC_VO, 7, 7,
1951 pHddCtx->config->InfraUapsdVoSrvIntv,
1952 pHddCtx->config->InfraUapsdVoSuspIntv,
1953 SME_BI_DIR, 1,
1954 pAdapter->sessionId,
1955 pHddCtx->config->DelayedTriggerFrmInt);
1956
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301957 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958 }
1959
1960 if (uapsdMask & HDD_AC_VI) {
1961 status =
1962 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1963 pcds_context,
1964 (WLAN_HDD_GET_STATION_CTX_PTR
1965 (pAdapter))->conn_info.staId[0],
1966 SME_AC_VI, 5, 5,
1967 pHddCtx->config->InfraUapsdViSrvIntv,
1968 pHddCtx->config->InfraUapsdViSuspIntv,
1969 SME_BI_DIR, 1,
1970 pAdapter->sessionId,
1971 pHddCtx->config->DelayedTriggerFrmInt);
1972
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301973 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001974 }
1975
1976 if (uapsdMask & HDD_AC_BK) {
1977 status =
1978 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1979 pcds_context,
1980 (WLAN_HDD_GET_STATION_CTX_PTR
1981 (pAdapter))->conn_info.staId[0],
1982 SME_AC_BK, 2, 2,
1983 pHddCtx->config->InfraUapsdBkSrvIntv,
1984 pHddCtx->config->InfraUapsdBkSuspIntv,
1985 SME_BI_DIR, 1,
1986 pAdapter->sessionId,
1987 pHddCtx->config->DelayedTriggerFrmInt);
1988
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301989 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001990 }
1991
1992 if (uapsdMask & HDD_AC_BE) {
1993 status =
1994 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1995 pcds_context,
1996 (WLAN_HDD_GET_STATION_CTX_PTR
1997 (pAdapter))->conn_info.staId[0],
1998 SME_AC_BE, 3, 3,
1999 pHddCtx->config->InfraUapsdBeSrvIntv,
2000 pHddCtx->config->InfraUapsdBeSuspIntv,
2001 SME_BI_DIR, 1,
2002 pAdapter->sessionId,
2003 pHddCtx->config->DelayedTriggerFrmInt);
2004
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302005 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002006 }
2007
2008 status = sme_update_dsc_pto_up_mapping(pHddCtx->hHal,
2009 pAdapter->hddWmmDscpToUpMap,
2010 pAdapter->sessionId);
2011
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302012 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002013 hdd_wmm_init(pAdapter);
2014 }
2015
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302016 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002017 "%s: Exiting", __func__);
2018
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302019 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002020}
2021
2022static const uint8_t acm_mask_bit[WLAN_MAX_AC] = {
2023 0x4, /* SME_AC_BK */
2024 0x8, /* SME_AC_BE */
2025 0x2, /* SME_AC_VI */
2026 0x1 /* SME_AC_VO */
2027};
2028
2029/**
2030 * hdd_wmm_connect() - Function which will handle the housekeeping
2031 * required by WMM when a connection is established
2032 *
2033 * @pAdapter : [in] pointer to adapter context
2034 * @pRoamInfo: [in] pointer to roam information
2035 * @eBssType : [in] type of BSS
2036 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302037 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302039QDF_STATUS hdd_wmm_connect(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002040 tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType)
2041{
2042 int ac;
2043 bool qap;
2044 bool qosConnection;
2045 uint8_t acmMask;
2046
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302047 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002048 "%s: Entered", __func__);
2049
2050 if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) &&
2051 pRoamInfo && pRoamInfo->u.pConnectedProfile) {
2052 qap = pRoamInfo->u.pConnectedProfile->qap;
2053 qosConnection = pRoamInfo->u.pConnectedProfile->qosConnection;
2054 acmMask = pRoamInfo->u.pConnectedProfile->acm_mask;
2055 } else {
2056 qap = true;
2057 qosConnection = true;
2058 acmMask = 0x0;
2059 }
2060
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302061 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002062 "%s: qap is %d, qosConnection is %d, acmMask is 0x%x",
2063 __func__, qap, qosConnection, acmMask);
2064
2065 pAdapter->hddWmmStatus.wmmQap = qap;
2066 pAdapter->hddWmmStatus.wmmQosConnection = qosConnection;
2067
2068 for (ac = 0; ac < WLAN_MAX_AC; ac++) {
2069 if (qap && qosConnection && (acmMask & acm_mask_bit[ac])) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302070 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002071 "%s: ac %d on", __func__, ac);
2072
2073 /* admission is required */
2074 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2075 wmmAcAccessRequired = true;
2076 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2077 wmmAcAccessAllowed = false;
2078 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2079 wmmAcAccessGranted = false;
2080 /* after reassoc if we have valid tspec, allow access */
2081 if (pAdapter->hddWmmStatus.wmmAcStatus[ac].
2082 wmmAcTspecValid
2083 && (pAdapter->hddWmmStatus.wmmAcStatus[ac].
2084 wmmAcTspecInfo.ts_info.direction !=
2085 SME_QOS_WMM_TS_DIR_DOWNLINK)) {
2086 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2087 wmmAcAccessAllowed = true;
2088 }
2089 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302090 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002091 "%s: ac %d off", __func__, ac);
2092 /* admission is not required so access is allowed */
2093 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2094 wmmAcAccessRequired = false;
2095 pAdapter->hddWmmStatus.wmmAcStatus[ac].
2096 wmmAcAccessAllowed = true;
2097 }
2098
2099 }
2100
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302101 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002102 "%s: Exiting", __func__);
2103
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302104 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002105}
2106
2107/**
2108 * hdd_wmm_get_uapsd_mask() - Function which will calculate the
2109 * initial value of the UAPSD mask based upon the device configuration
2110 *
2111 * @pAdapter : [in] pointer to adapter context
2112 * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored
2113 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302114 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002115 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302116QDF_STATUS hdd_wmm_get_uapsd_mask(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002117 uint8_t *pUapsdMask)
2118{
2119 uint8_t uapsdMask;
2120
2121 if (HDD_WMM_USER_MODE_NO_QOS ==
2122 (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) {
2123 /* no QOS then no UAPSD */
2124 uapsdMask = 0;
2125 } else {
2126 /* start with the default mask */
2127 uapsdMask = (WLAN_HDD_GET_CTX(pAdapter))->config->UapsdMask;
2128
2129 /* disable UAPSD for any ACs with a 0 Service Interval */
2130 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2131 InfraUapsdVoSrvIntv == 0) {
2132 uapsdMask &= ~HDD_AC_VO;
2133 }
2134
2135 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2136 InfraUapsdViSrvIntv == 0) {
2137 uapsdMask &= ~HDD_AC_VI;
2138 }
2139
2140 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2141 InfraUapsdBkSrvIntv == 0) {
2142 uapsdMask &= ~HDD_AC_BK;
2143 }
2144
2145 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2146 InfraUapsdBeSrvIntv == 0) {
2147 uapsdMask &= ~HDD_AC_BE;
2148 }
2149 }
2150
2151 /* return calculated mask */
2152 *pUapsdMask = uapsdMask;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302153 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002154}
2155
2156/**
2157 * hdd_wmm_is_active() - Function which will determine if WMM is
2158 * active on the current connection
2159 *
2160 * @pAdapter: [in] pointer to adapter context
2161 *
2162 * Return: true if WMM is enabled, false if WMM is not enabled
2163 */
2164bool hdd_wmm_is_active(hdd_adapter_t *pAdapter)
2165{
2166 if ((!pAdapter->hddWmmStatus.wmmQosConnection) ||
2167 (!pAdapter->hddWmmStatus.wmmQap)) {
2168 return false;
2169 } else {
2170 return true;
2171 }
2172}
2173
2174/**
2175 * hdd_wmm_addts() - Function which will add a traffic spec at the
2176 * request of an application
2177 *
2178 * @pAdapter : [in] pointer to adapter context
2179 * @handle : [in] handle to uniquely identify a TS
2180 * @pTspec : [in] pointer to the traffic spec
2181 *
2182 * Return: HDD_WLAN_WMM_STATUS_*
2183 */
2184hdd_wlan_wmm_status_e hdd_wmm_addts(hdd_adapter_t *pAdapter,
2185 uint32_t handle,
2186 sme_QosWmmTspecInfo *pTspec)
2187{
2188 hdd_wmm_qos_context_t *pQosContext;
2189 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2190#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2191 sme_QosStatusType smeStatus;
2192#endif
2193 bool found = false;
2194
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302195 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002196 "%s: Entered with handle 0x%x", __func__, handle);
2197
2198 /* see if a context already exists with the given handle */
2199 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2200 list_for_each_entry(pQosContext,
2201 &pAdapter->hddWmmStatus.wmmContextList, node) {
2202 if (pQosContext->handle == handle) {
2203 found = true;
2204 break;
2205 }
2206 }
2207 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2208 if (found) {
2209 /* record with that handle already exists */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302210 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002211 "%s: Record already exists with handle 0x%x",
2212 __func__, handle);
2213
2214 /* Application is trying to modify some of the Tspec
2215 * params. Allow it
2216 */
2217 smeStatus = sme_qos_modify_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
2218 pTspec, pQosContext->qosFlowId);
2219
2220 /* need to check the return value and act appropriately */
2221 switch (smeStatus) {
2222 case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
2223 status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING;
2224 break;
2225 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2226 status =
2227 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
2228 break;
2229 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
2230 status =
2231 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
2232 break;
2233 case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
2234 status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
2235 break;
2236 case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
2237 status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2238 break;
2239 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2240 status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2241 break;
2242 default:
2243 /* we didn't get back one of the
2244 * SME_QOS_STATUS_MODIFY_* status codes
2245 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302246 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002247 "%s: unexpected SME Status=%d", __func__,
2248 smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302249 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002250 return HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2251 }
2252
2253 /* we were successful, save the status */
2254 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2255 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2256 pQosContext->lastStatus = status;
2257 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2258
2259 return status;
2260 }
2261
2262 pQosContext = kmalloc(sizeof(*pQosContext), GFP_KERNEL);
2263 if (NULL == pQosContext) {
2264 /* no memory for QoS context. Nothing we can do */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302265 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002266 "%s: Unable to allocate QoS context", __func__);
2267 return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE;
2268 }
2269 /* we assume the tspec has already been validated by the caller */
2270
2271 pQosContext->handle = handle;
2272 if (pTspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE)
2273 pQosContext->acType = hdd_wmm_up_to_ac_map[pTspec->ts_info.up];
2274 else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302275 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002276 "%s: ts_info.up (%d) larger than max value (%d), use default acType (%d)",
2277 __func__, pTspec->ts_info.up,
2278 HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]);
2279 pQosContext->acType = hdd_wmm_up_to_ac_map[0];
2280 }
2281 pQosContext->pAdapter = pAdapter;
2282 pQosContext->qosFlowId = 0;
2283 pQosContext->magic = HDD_WMM_CTX_MAGIC;
2284
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302285 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002286 "%s: Setting up QoS, context %p", __func__, pQosContext);
2287
2288 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2289 list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList);
2290 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2291
2292#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2293 smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
2294 pAdapter->sessionId,
2295 pTspec,
2296 hdd_wmm_sme_callback,
2297 pQosContext,
2298 pTspec->ts_info.up,
2299 &pQosContext->qosFlowId);
2300
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302301 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002302 "%s: sme_qos_setup_req returned %d flowid %d",
2303 __func__, smeStatus, pQosContext->qosFlowId);
2304
2305 /* need to check the return value and act appropriately */
2306 switch (smeStatus) {
2307 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
2308 status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2309 break;
2310 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2311 status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
2312 break;
2313 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
2314 status =
2315 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
2316 break;
2317 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
2318 status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2319 break;
2320 case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
2321 hdd_wmm_free_context(pQosContext);
2322 return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
2323 case SME_QOS_STATUS_SETUP_FAILURE_RSP:
2324 /* we can't tell the difference between when a request
2325 * fails because AP rejected it versus when SME
2326 * encounterd an internal error
2327 */
2328 hdd_wmm_free_context(pQosContext);
2329 return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2330 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2331 hdd_wmm_free_context(pQosContext);
2332 return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2333 default:
2334 /* we didn't get back one of the
2335 * SME_QOS_STATUS_SETUP_* status codes
2336 */
2337 hdd_wmm_free_context(pQosContext);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302338 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002339 "%s: unexpected SME Status=%d", __func__, smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302340 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002341 return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2342 }
2343#endif
2344
2345 /* we were successful, save the status */
2346 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2347 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2348 pQosContext->lastStatus = status;
2349 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2350
2351 return status;
2352}
2353
2354/**
2355 * hdd_wmm_delts() - Function which will delete a traffic spec at the
2356 * request of an application
2357 *
2358 * @pAdapter: [in] pointer to adapter context
2359 * @handle: [in] handle to uniquely identify a TS
2360 *
2361 * Return: HDD_WLAN_WMM_STATUS_*
2362 */
2363hdd_wlan_wmm_status_e hdd_wmm_delts(hdd_adapter_t *pAdapter, uint32_t handle)
2364{
2365 hdd_wmm_qos_context_t *pQosContext;
2366 bool found = false;
2367 sme_ac_enum_type acType = 0;
2368 uint32_t qosFlowId = 0;
2369 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2370#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2371 sme_QosStatusType smeStatus;
2372#endif
2373
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302374 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002375 "%s: Entered with handle 0x%x", __func__, handle);
2376
2377 /* locate the context with the given handle */
2378 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2379 list_for_each_entry(pQosContext,
2380 &pAdapter->hddWmmStatus.wmmContextList, node) {
2381 if (pQosContext->handle == handle) {
2382 found = true;
2383 acType = pQosContext->acType;
2384 qosFlowId = pQosContext->qosFlowId;
2385 break;
2386 }
2387 }
2388 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2389
2390 if (false == found) {
2391 /* we didn't find the handle */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302392 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002393 "%s: handle 0x%x not found", __func__, handle);
2394 return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2395 }
2396
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302397 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002398 "%s: found handle 0x%x, flow %d, AC %d, context %p",
2399 __func__, handle, qosFlowId, acType, pQosContext);
2400
2401#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2402 smeStatus =
2403 sme_qos_release_req(WLAN_HDD_GET_HAL_CTX(pAdapter), qosFlowId);
2404
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302405 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002406 "%s: SME flow %d released, SME status %d",
2407 __func__, qosFlowId, smeStatus);
2408
2409 switch (smeStatus) {
2410 case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
2411 /* this flow is the only one on that AC, so go ahead
2412 * and update our TSPEC state for the AC
2413 */
2414 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcTspecValid =
2415 false;
Sreelakshmi Konamki9d6b75d2016-02-10 12:17:23 +05302416 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed =
2417 false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002418
2419 /* need to tell TL to stop trigger timer, etc */
2420 hdd_wmm_disable_tl_uapsd(pQosContext);
2421
2422#ifdef FEATURE_WLAN_ESE
2423 /* disable the inactivity timer */
2424 hdd_wmm_disable_inactivity_timer(pQosContext);
2425#endif
2426 /* we are done with this context */
2427 hdd_wmm_free_context(pQosContext);
2428
2429 /* SME must not fire any more callbacks for this flow
2430 * since the context is no longer valid
2431 */
2432
2433 return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
2434
2435 case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
2436 /* do nothing as we will get a response from SME */
2437 status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING;
2438 break;
2439
2440 case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
2441 /* nothing we can do with the existing flow except leave it */
2442 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2443 break;
2444
2445 case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
2446 /* nothing we can do with the existing flow except leave it */
2447 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2448
2449 default:
2450 /* we didn't get back one of the
2451 * SME_QOS_STATUS_RELEASE_* status codes
2452 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302453 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002454 "%s: unexpected SME Status=%d", __func__, smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302455 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002456 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2457 }
2458
2459#endif
2460 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2461 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2462 pQosContext->lastStatus = status;
2463 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2464
2465 return status;
2466}
2467
2468/**
2469 * hdd_wmm_checkts() - Function which will return the status of a traffic
2470 * spec at the request of an application
2471 *
2472 * @pAdapter: [in] pointer to adapter context
2473 * @handle: [in] handle to uniquely identify a TS
2474 *
2475 * Return: HDD_WLAN_WMM_STATUS_*
2476 */
2477hdd_wlan_wmm_status_e hdd_wmm_checkts(hdd_adapter_t *pAdapter, uint32_t handle)
2478{
2479 hdd_wmm_qos_context_t *pQosContext;
2480 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST;
2481
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302482 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002483 "%s: Entered with handle 0x%x", __func__, handle);
2484
2485 /* locate the context with the given handle */
2486 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2487 list_for_each_entry(pQosContext,
2488 &pAdapter->hddWmmStatus.wmmContextList, node) {
2489 if (pQosContext->handle == handle) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302490 QDF_TRACE(QDF_MODULE_ID_HDD, WMM_TRACE_LEVEL_INFO_LOW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002491 "%s: found handle 0x%x, context %p",
2492 __func__, handle, pQosContext);
2493
2494 status = pQosContext->lastStatus;
2495 break;
2496 }
2497 }
2498 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2499 return status;
2500}