blob: f7beedff0de72da5a467aa6715b1e3ec7a3f94cf [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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080065#define WLAN_HDD_MAX_DSCP 0x3f
66
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080067#define HDD_WMM_UP_TO_AC_MAP_SIZE 8
68
69const uint8_t hdd_wmm_up_to_ac_map[] = {
70 SME_AC_BE,
71 SME_AC_BK,
72 SME_AC_BK,
73 SME_AC_BE,
74 SME_AC_VI,
75 SME_AC_VI,
76 SME_AC_VO,
77 SME_AC_VO
78};
79
80/**
81 * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to
82 * operate on different traffic.
83 */
84#ifdef QCA_LL_TX_FLOW_CONTROL_V2
85enum hdd_wmm_linuxac {
86 HDD_LINUX_AC_VO = 0,
87 HDD_LINUX_AC_VI = 1,
88 HDD_LINUX_AC_BE = 2,
89 HDD_LINUX_AC_BK = 3,
90 HDD_LINUX_AC_HI_PRIO = 4,
91};
92
93void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter)
94{
95 /* Enable HI_PRIO queue */
96 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VO);
97 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VI);
98 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BE);
99 netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BK);
100 netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO);
101
102}
103#else
104enum hdd_wmm_linuxac {
105 HDD_LINUX_AC_VO = 0,
106 HDD_LINUX_AC_VI = 1,
107 HDD_LINUX_AC_BE = 2,
108 HDD_LINUX_AC_BK = 3
109};
110
111void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter)
112{
113 return;
114}
115#endif
116
117/* Linux based UP -> AC Mapping */
118const uint8_t hdd_linux_up_to_ac_map[HDD_WMM_UP_TO_AC_MAP_SIZE] = {
119 HDD_LINUX_AC_BE,
120 HDD_LINUX_AC_BK,
121 HDD_LINUX_AC_BK,
122 HDD_LINUX_AC_BE,
123 HDD_LINUX_AC_VI,
124 HDD_LINUX_AC_VI,
125 HDD_LINUX_AC_VO,
126 HDD_LINUX_AC_VO
127};
128
129#ifndef WLAN_MDM_CODE_REDUCTION_OPT
130/**
131 * hdd_wmm_enable_tl_uapsd() - function which decides whether and
132 * how to update UAPSD parameters in TL
133 *
134 * @pQosContext: [in] the pointer the QoS instance control block
135 *
136 * Return: None
137 */
138static void hdd_wmm_enable_tl_uapsd(hdd_wmm_qos_context_t *pQosContext)
139{
140 hdd_adapter_t *pAdapter = pQosContext->pAdapter;
141 sme_ac_enum_type acType = pQosContext->acType;
142 hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
143 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530144 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800145 uint32_t service_interval;
146 uint32_t suspension_interval;
147 sme_QosWmmDirType direction;
148 bool psb;
149
150 /* The TSPEC must be valid */
151 if (pAc->wmmAcTspecValid == false) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700152 hdd_err("Invoked with invalid TSPEC");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800153 return;
154 }
155 /* determine the service interval */
156 if (pAc->wmmAcTspecInfo.min_service_interval) {
157 service_interval = pAc->wmmAcTspecInfo.min_service_interval;
158 } else if (pAc->wmmAcTspecInfo.max_service_interval) {
159 service_interval = pAc->wmmAcTspecInfo.max_service_interval;
160 } else {
161 /* no service interval is present in the TSPEC */
162 /* this is OK, there just won't be U-APSD */
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700163 hdd_notice("No service interval supplied");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800164 service_interval = 0;
165 }
166
167 /* determine the suspension interval & direction */
168 suspension_interval = pAc->wmmAcTspecInfo.suspension_interval;
169 direction = pAc->wmmAcTspecInfo.ts_info.direction;
170 psb = pAc->wmmAcTspecInfo.ts_info.psb;
171
172 /* if we have previously enabled U-APSD, have any params changed? */
173 if ((pAc->wmmAcUapsdInfoValid) &&
174 (pAc->wmmAcUapsdServiceInterval == service_interval) &&
175 (pAc->wmmAcUapsdSuspensionInterval == suspension_interval) &&
176 (pAc->wmmAcUapsdDirection == direction) &&
177 (pAc->wmmAcIsUapsdEnabled == psb)) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700178 hdd_notice("No change in U-APSD parameters");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800179 return;
180 }
181 /* everything is in place to notify TL */
182 status =
183 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->pcds_context,
184 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->
185 conn_info.staId[0], acType,
186 pAc->wmmAcTspecInfo.ts_info.tid,
187 pAc->wmmAcTspecInfo.ts_info.up,
188 service_interval, suspension_interval,
189 direction, psb, pAdapter->sessionId,
190 pHddCtx->config->DelayedTriggerFrmInt);
191
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530192 if (!QDF_IS_STATUS_SUCCESS(status)) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700193 hdd_err("Failed to enable U-APSD for AC=%d", acType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194 return;
195 }
196 /* stash away the parameters that were used */
197 pAc->wmmAcUapsdInfoValid = true;
198 pAc->wmmAcUapsdServiceInterval = service_interval;
199 pAc->wmmAcUapsdSuspensionInterval = suspension_interval;
200 pAc->wmmAcUapsdDirection = direction;
201 pAc->wmmAcIsUapsdEnabled = psb;
202
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700203 hdd_notice("Enabled UAPSD in TL srv_int=%d susp_int=%d dir=%d AC=%d",
204 service_interval, suspension_interval, direction, acType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800205
206}
207
208/**
209 * hdd_wmm_disable_tl_uapsd() - function which decides whether
210 * to disable UAPSD parameters in TL
211 *
212 * @pQosContext: [in] the pointer the QoS instance control block
213 *
214 * Return: None
215 */
216static void hdd_wmm_disable_tl_uapsd(hdd_wmm_qos_context_t *pQosContext)
217{
218 hdd_adapter_t *pAdapter = pQosContext->pAdapter;
219 sme_ac_enum_type acType = pQosContext->acType;
220 hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530221 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800222
223 /* have we previously enabled UAPSD? */
224 if (pAc->wmmAcUapsdInfoValid == true) {
Sreelakshmi Konamkie1ce5622015-11-23 15:04:05 +0530225 status =
226 sme_disable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
227 pcds_context,
228 (WLAN_HDD_GET_STATION_CTX_PTR
229 (pAdapter))->conn_info.staId[0],
230 acType, pAdapter->sessionId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800231
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530232 if (!QDF_IS_STATUS_SUCCESS(status)) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700233 hdd_err("Failed to disable U-APSD for AC=%d", acType);
Sreelakshmi Konamkie1ce5622015-11-23 15:04:05 +0530234 } else {
235 /* TL no longer has valid UAPSD info */
236 pAc->wmmAcUapsdInfoValid = false;
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700237 hdd_notice("Disabled UAPSD in TL for AC=%d", acType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800238 }
239 }
240}
241
242#endif
243
244/**
245 * hdd_wmm_free_context() - function which frees a QoS context
246 *
247 * @pQosContext: [in] the pointer the QoS instance control block
248 *
249 * Return: None
250 */
251static void hdd_wmm_free_context(hdd_wmm_qos_context_t *pQosContext)
252{
253 hdd_adapter_t *pAdapter;
254
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700255 hdd_info("Entered, context %p", pQosContext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800256
257 if (unlikely((NULL == pQosContext) ||
258 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
259 /* must have been freed in another thread */
260 return;
261 }
262 /* get pointer to the adapter context */
263 pAdapter = pQosContext->pAdapter;
264
265 /* take the wmmLock since we're manipulating the context list */
266 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
267
268 /* make sure nobody thinks this is a valid context */
269 pQosContext->magic = 0;
270
271 /* unlink the context */
272 list_del(&pQosContext->node);
273
274 /* done manipulating the list */
275 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
276
277 /* reclaim memory */
278 kfree(pQosContext);
279
280}
281
282#ifndef WLAN_MDM_CODE_REDUCTION_OPT
283/**
284 * hdd_wmm_notify_app() - function which notifies an application
285 * of changes in state of it flow
286 *
287 * @pQosContext: [in] the pointer the QoS instance control block
288 *
289 * Return: None
290 */
291#define MAX_NOTIFY_LEN 50
292static void hdd_wmm_notify_app(hdd_wmm_qos_context_t *pQosContext)
293{
294 hdd_adapter_t *pAdapter;
295 union iwreq_data wrqu;
296 char buf[MAX_NOTIFY_LEN + 1];
297
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700298 hdd_info("Entered, context %p", pQosContext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800299
300 if (unlikely((NULL == pQosContext) ||
301 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700302 hdd_err("Invalid QoS Context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800303 return;
304 }
305
306 /* create the event */
307 memset(&wrqu, 0, sizeof(wrqu));
308 memset(buf, 0, sizeof(buf));
309
310 snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]",
311 (unsigned int)pQosContext->handle,
312 (unsigned int)pQosContext->lastStatus);
313
314 wrqu.data.pointer = buf;
315 wrqu.data.length = strlen(buf);
316
317 /* get pointer to the adapter */
318 pAdapter = pQosContext->pAdapter;
319
320 /* send the event */
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700321 hdd_notice("Sending [%s]", buf);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800322 wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf);
323}
324
325#ifdef FEATURE_WLAN_ESE
326/**
327 * hdd_wmm_inactivity_timer_cb() - inactivity timer callback function
328 *
329 * @user_data: opaque user data registered with the timer. In the
330 * case of this timer, the associated wmm QoS context is registered.
331 *
332 * This timer handler function is called for every inactivity interval
333 * per AC. This function gets the current transmitted packets on the
334 * given AC, and checks if there was any TX activity from the previous
335 * interval. If there was no traffic then it would delete the TS that
336 * was negotiated on that AC.
337 *
338 * Return: None
339 */
340static void hdd_wmm_inactivity_timer_cb(void *user_data)
341{
342 hdd_wmm_qos_context_t *pQosContext = user_data;
343 hdd_adapter_t *pAdapter;
344 hdd_wmm_ac_status_t *pAc;
345 hdd_wlan_wmm_status_e status;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530346 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800347 uint32_t currentTrafficCnt = 0;
348 sme_ac_enum_type acType = pQosContext->acType;
349
350 pAdapter = pQosContext->pAdapter;
c_hpothud5009242016-08-18 12:10:36 +0530351 if ((NULL == pAdapter) ||
352 (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) {
353 hdd_err("invalid pAdapter: %p", pAdapter);
354 return;
355 }
356
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800357 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
358
359 /* Get the Tx stats for this AC. */
360 currentTrafficCnt =
361 pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext->
362 acType];
363
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700364 hdd_warn("WMM inactivity Timer for AC=%d, currentCnt=%d, prevCnt=%d",
365 acType, (int)currentTrafficCnt, (int)pAc->wmmPrevTrafficCnt);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800366 if (pAc->wmmPrevTrafficCnt == currentTrafficCnt) {
367 /* there is no traffic activity, delete the TSPEC for this AC */
368 status = hdd_wmm_delts(pAdapter, pQosContext->handle);
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700369 hdd_warn("Deleted TS on AC %d, due to inactivity with status = %d!!!",
370 acType, status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800371 } else {
372 pAc->wmmPrevTrafficCnt = currentTrafficCnt;
Anurag Chouhan210db072016-02-22 18:42:15 +0530373 if (pAc->wmmInactivityTimer.state == QDF_TIMER_STATE_STOPPED) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800374 /* Restart the timer */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530375 qdf_status =
Anurag Chouhan210db072016-02-22 18:42:15 +0530376 qdf_mc_timer_start(&pAc->wmmInactivityTimer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800377 pAc->wmmInactivityTime);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530378 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700379 hdd_err("Restarting inactivity timer failed on AC %d",
380 acType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800381 }
382 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530383 QDF_ASSERT(qdf_mc_timer_get_current_state
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800384 (&pAc->wmmInactivityTimer) ==
Anurag Chouhan210db072016-02-22 18:42:15 +0530385 QDF_TIMER_STATE_STOPPED);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800386 }
387 }
388
389 return;
390}
391
392/**
393 * hdd_wmm_enable_inactivity_timer() -
394 * function to enable the traffic inactivity timer for the given AC
395 *
396 * @pQosContext: [in] pointer to pQosContext
397 * @inactivityTime: [in] value of the inactivity interval in millisecs
398 *
399 * When a QoS-Tspec is successfully setup, if the inactivity interval
400 * time specified in the AddTS parameters is non-zero, this function
401 * is invoked to start a traffic inactivity timer for the given AC.
402 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530403 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800404 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530405static QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800406hdd_wmm_enable_inactivity_timer(hdd_wmm_qos_context_t *pQosContext,
407 uint32_t inactivityTime)
408{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530409 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800410 hdd_adapter_t *pAdapter = pQosContext->pAdapter;
411 sme_ac_enum_type acType = pQosContext->acType;
412 hdd_wmm_ac_status_t *pAc;
413
414 pAdapter = pQosContext->pAdapter;
415 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
416
Anurag Chouhan210db072016-02-22 18:42:15 +0530417 qdf_status = qdf_mc_timer_init(&pAc->wmmInactivityTimer,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530418 QDF_TIMER_TYPE_SW,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800419 hdd_wmm_inactivity_timer_cb,
420 pQosContext);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530421 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700422 hdd_err("Initializing inactivity timer failed on AC %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 acType);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530424 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800425 }
426 /* Start the inactivity timer */
Anurag Chouhan210db072016-02-22 18:42:15 +0530427 qdf_status = qdf_mc_timer_start(&pAc->wmmInactivityTimer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800428 inactivityTime);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530429 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700430 hdd_err("Starting inactivity timer failed on AC %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431 acType);
Anurag Chouhan210db072016-02-22 18:42:15 +0530432 qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530433 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800434 hdd_err("Failed to destroy inactivity timer");
435 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530436 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800437 }
438 pAc->wmmInactivityTime = inactivityTime;
439 /* Initialize the current tx traffic count on this AC */
440 pAc->wmmPrevTrafficCnt =
441 pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext->
442 acType];
443 pQosContext->is_inactivity_timer_running = true;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530444 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800445}
446
447/**
448 * hdd_wmm_disable_inactivity_timer() -
449 * function to disable the traffic inactivity timer for the given AC.
450 *
451 * @pQosContext: [in] pointer to pQosContext
452 *
453 * This function is invoked to disable the traffic inactivity timer
454 * for the given AC. This is normally done when the TS is deleted.
455 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530456 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800457 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530458static QDF_STATUS
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800459hdd_wmm_disable_inactivity_timer(hdd_wmm_qos_context_t *pQosContext)
460{
461 hdd_adapter_t *pAdapter = pQosContext->pAdapter;
462 sme_ac_enum_type acType = pQosContext->acType;
463 hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530464 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800465
466 /* Clear the timer and the counter */
467 pAc->wmmInactivityTime = 0;
468 pAc->wmmPrevTrafficCnt = 0;
469
470 if (pQosContext->is_inactivity_timer_running == true) {
471 pQosContext->is_inactivity_timer_running = false;
Anurag Chouhan210db072016-02-22 18:42:15 +0530472 qdf_status = qdf_mc_timer_stop(&pAc->wmmInactivityTimer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530473 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 hdd_err("Failed to stop inactivity timer");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530475 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 }
Anurag Chouhan210db072016-02-22 18:42:15 +0530477 qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530478 if (!QDF_IS_STATUS_SUCCESS(qdf_status))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800479 hdd_err("Failed to destroy inactivity timer:Timer started");
480 }
481
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530482 return qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800483}
484#endif /* FEATURE_WLAN_ESE */
485
486/**
487 * hdd_wmm_sme_callback() - callback for QoS notifications
488 *
489 * @hHal: [in] the HAL handle
490 * @hddCtx : [in] the HDD specified handle
491 * @pCurrentQosInfo : [in] the TSPEC params
492 * @smeStatus : [in] the QoS related SME status
493 * @qosFlowId: [in] the unique identifier of the flow
494 *
495 * This callback is registered by HDD with SME for receiving QoS
496 * notifications. Even though this function has a static scope it
497 * gets called externally through some function pointer magic (so
498 * there is a need for rigorous parameter checking).
499 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530500 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530502static QDF_STATUS hdd_wmm_sme_callback(tHalHandle hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800503 void *hddCtx,
504 sme_QosWmmTspecInfo *pCurrentQosInfo,
505 sme_QosStatusType smeStatus,
506 uint32_t qosFlowId)
507{
508 hdd_wmm_qos_context_t *pQosContext = hddCtx;
509 hdd_adapter_t *pAdapter;
510 sme_ac_enum_type acType;
511 hdd_wmm_ac_status_t *pAc;
512
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700513 hdd_info("Entered, context %p", pQosContext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800514
515 if (unlikely((NULL == pQosContext) ||
516 (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700517 hdd_err("Invalid QoS Context");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530518 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800519 }
520
521 pAdapter = pQosContext->pAdapter;
522 acType = pQosContext->acType;
523 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
524
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700525 hdd_info("status %d flowid %d info %p",
526 smeStatus, qosFlowId, pCurrentQosInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800527
528 switch (smeStatus) {
529
530 case SME_QOS_STATUS_SETUP_SUCCESS_IND:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700531 hdd_info("Setup is complete");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532
533 /* there will always be a TSPEC returned with this
534 * status, even if a TSPEC is not exchanged OTA
535 */
536 if (pCurrentQosInfo) {
537 pAc->wmmAcTspecValid = true;
538 memcpy(&pAc->wmmAcTspecInfo,
539 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
540 }
541 pAc->wmmAcAccessAllowed = true;
542 pAc->wmmAcAccessGranted = true;
543 pAc->wmmAcAccessPending = false;
544 pAc->wmmAcAccessFailed = false;
545
546 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
547
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700548 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800549
550 /* this was triggered by an application */
551 pQosContext->lastStatus =
552 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
553 hdd_wmm_notify_app(pQosContext);
554 }
555
556#ifdef FEATURE_WLAN_ESE
557 /* Check if the inactivity interval is specified */
558 if (pCurrentQosInfo && pCurrentQosInfo->inactivity_interval) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700559 hdd_notice("Inactivity timer value = %d for AC=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800560 pCurrentQosInfo->inactivity_interval, acType);
561 hdd_wmm_enable_inactivity_timer(pQosContext,
562 pCurrentQosInfo->
563 inactivity_interval);
564 }
565#endif /* FEATURE_WLAN_ESE */
566
567 /* notify TL to enable trigger frames if necessary */
568 hdd_wmm_enable_tl_uapsd(pQosContext);
569
570 break;
571
572 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700573 hdd_notice("Setup is complete (U-APSD set previously)");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800574
575 pAc->wmmAcAccessAllowed = true;
576 pAc->wmmAcAccessGranted = true;
577 pAc->wmmAcAccessPending = false;
578
579 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
580
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700581 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800582
583 /* this was triggered by an application */
584 pQosContext->lastStatus =
585 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
586 hdd_wmm_notify_app(pQosContext);
587 }
588
589 break;
590
591 case SME_QOS_STATUS_SETUP_FAILURE_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700592 hdd_err("Setup failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800593 /* QoS setup failed */
594
595 pAc->wmmAcAccessPending = false;
596 pAc->wmmAcAccessFailed = true;
597 pAc->wmmAcAccessAllowed = false;
598 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
599
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700600 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800601
602 /* this was triggered by an application */
603 pQosContext->lastStatus =
604 HDD_WLAN_WMM_STATUS_SETUP_FAILED;
605
606 hdd_wmm_notify_app(pQosContext);
607 }
608
609 /* Setting up QoS Failed, QoS context can be released.
610 * SME is releasing this flow information and if HDD
611 * doesn't release this context, next time if
612 * application uses the same handle to set-up QoS, HDD
613 * (as it has QoS context for this handle) will issue
614 * Modify QoS request to SME but SME will reject as now
615 * it has no information for this flow.
616 */
617 hdd_wmm_free_context(pQosContext);
618 break;
619
620 case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700621 hdd_err("Setup Invalid Params, notify TL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800622 /* QoS setup failed */
623 pAc->wmmAcAccessAllowed = false;
624
625 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
626
627 /* we note the failure, but we also mark
628 * access as allowed so that the packets will
629 * flow. Note that the MAC will "do the right
630 * thing"
631 */
632 pAc->wmmAcAccessPending = false;
633 pAc->wmmAcAccessFailed = true;
634 pAc->wmmAcAccessAllowed = true;
635
636 } else {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700637 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800638
639 /* this was triggered by an application */
640 pQosContext->lastStatus =
641 HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
642 hdd_wmm_notify_app(pQosContext);
643 }
644 break;
645
646 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700647 hdd_err("Setup failed, not a QoS AP");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800648 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700649 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800650
651 /* this was triggered by an application */
652 pQosContext->lastStatus =
653 HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
654 hdd_wmm_notify_app(pQosContext);
655 }
656 break;
657
658 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700659 hdd_notice("Setup pending");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800660 /* not a callback status -- ignore if we get it */
661 break;
662
663 case SME_QOS_STATUS_SETUP_MODIFIED_IND:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700664 hdd_notice("Setup modified");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800665 if (pCurrentQosInfo) {
666 /* update the TSPEC */
667 pAc->wmmAcTspecValid = true;
668 memcpy(&pAc->wmmAcTspecInfo,
669 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
670
671 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700672 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800673
674 /* this was triggered by an application */
675 pQosContext->lastStatus =
676 HDD_WLAN_WMM_STATUS_MODIFIED;
677 hdd_wmm_notify_app(pQosContext);
678 }
679 /* need to tell TL to update its UAPSD handling */
680 hdd_wmm_enable_tl_uapsd(pQosContext);
681 }
682 break;
683
684 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
685 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
686
687 /* this was triggered by implicit QoS so we
688 * know packets are pending
689 */
690 pAc->wmmAcAccessPending = false;
691 pAc->wmmAcAccessGranted = true;
692 pAc->wmmAcAccessAllowed = true;
693
694 } else {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700695 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800696
697 /* this was triggered by an application */
698 pQosContext->lastStatus =
699 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
700 hdd_wmm_notify_app(pQosContext);
701 }
702 break;
703
704 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
705 /* nothing to do for now */
706 break;
707
708 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700709 hdd_err("Setup successful but U-APSD failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800710
711 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
712
713 /* QoS setup was successful but setting U=APSD
714 * failed. Since the OTA part of the request
715 * was successful, we don't mark this as a
716 * failure. the packets will flow. Note that
717 * the MAC will "do the right thing" */
718 pAc->wmmAcAccessGranted = true;
719 pAc->wmmAcAccessAllowed = true;
720 pAc->wmmAcAccessFailed = false;
721 pAc->wmmAcAccessPending = false;
722
723 } else {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700724 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800725
726 /* this was triggered by an application */
727 pQosContext->lastStatus =
728 HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED;
729 hdd_wmm_notify_app(pQosContext);
730 }
731
732 /* Since U-APSD portion failed disabled trigger frame
733 * generation
734 */
735 hdd_wmm_disable_tl_uapsd(pQosContext);
736
737 break;
738
739 case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700740 hdd_notice("Release is complete");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800741
742 if (pCurrentQosInfo) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700743 hdd_notice("flows still active");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800744
745 /* there is still at least one flow active for
746 * this AC so update the AC state
747 */
748 memcpy(&pAc->wmmAcTspecInfo,
749 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
750
751 /* need to tell TL to update its UAPSD handling */
752 hdd_wmm_enable_tl_uapsd(pQosContext);
753 } else {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700754 hdd_notice("last flow");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800755
756 /* this is the last flow active for this AC so
757 * update the AC state
758 */
759 pAc->wmmAcTspecValid = false;
760
761 /* DELTS is successful, do not allow */
762 pAc->wmmAcAccessAllowed = false;
763
764 /* need to tell TL to update its UAPSD handling */
765 hdd_wmm_disable_tl_uapsd(pQosContext);
766 }
767
768 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700769 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800770
771 /* this was triggered by an application */
772 pQosContext->lastStatus =
773 HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
774 hdd_wmm_notify_app(pQosContext);
775 }
776 /* we are done with this flow */
777 hdd_wmm_free_context(pQosContext);
778 break;
779
780 case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700781 hdd_notice("Release failure");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800782
783 /* we don't need to update our state or TL since
784 * nothing has changed
785 */
786 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700787 hdd_notice("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800788
789 /* this was triggered by an application */
790 pQosContext->lastStatus =
791 HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
792 hdd_wmm_notify_app(pQosContext);
793 }
794
795 break;
796
797 case SME_QOS_STATUS_RELEASE_QOS_LOST_IND:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700798 hdd_notice("QOS Lost indication received");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799
800 /* current TSPEC is no longer valid */
801 pAc->wmmAcTspecValid = false;
802 /* AP has sent DELTS, do not allow */
803 pAc->wmmAcAccessAllowed = false;
804
805 /* need to tell TL to update its UAPSD handling */
806 hdd_wmm_disable_tl_uapsd(pQosContext);
807
808 if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
809 /* we no longer have implicit access granted */
810 pAc->wmmAcAccessGranted = false;
811 pAc->wmmAcAccessFailed = false;
812 } else {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700813 hdd_info("Explicit Qos, notifying user space");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800814
815 /* this was triggered by an application */
816 pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_LOST;
817 hdd_wmm_notify_app(pQosContext);
818 }
819
820 /* we are done with this flow */
821 hdd_wmm_free_context(pQosContext);
822 break;
823
824 case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700825 hdd_info("Release pending");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826 /* not a callback status -- ignore if we get it */
827 break;
828
829 case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700830 hdd_err("Release Invalid Params");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
832 /* this was triggered by an application */
833 pQosContext->lastStatus =
834 HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
835 hdd_wmm_notify_app(pQosContext);
836 }
837 break;
838
839 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700840 hdd_info("Modification is complete, notify TL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800841
842 /* there will always be a TSPEC returned with this
843 * status, even if a TSPEC is not exchanged OTA
844 */
845 if (pCurrentQosInfo) {
846 pAc->wmmAcTspecValid = true;
847 memcpy(&pAc->wmmAcTspecInfo,
848 pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
849 }
850
851 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
852 /* this was triggered by an application */
853 pQosContext->lastStatus =
854 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS;
855 hdd_wmm_notify_app(pQosContext);
856 }
857 /* notify TL to enable trigger frames if necessary */
858 hdd_wmm_enable_tl_uapsd(pQosContext);
859
860 break;
861
862 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
863 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
864 /* this was triggered by an application */
865 pQosContext->lastStatus =
866 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
867 hdd_wmm_notify_app(pQosContext);
868 }
869 break;
870
871 case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
872 /* the flow modification failed so we'll leave in
873 * place whatever existed beforehand
874 */
875
876 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
877 /* this was triggered by an application */
878 pQosContext->lastStatus =
879 HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
880 hdd_wmm_notify_app(pQosContext);
881 }
882 break;
883
884 case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700885 hdd_info("modification pending");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886 /* not a callback status -- ignore if we get it */
887 break;
888
889 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
890 /* the flow modification was successful but no QoS
891 * changes required
892 */
893
894 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
895 /* this was triggered by an application */
896 pQosContext->lastStatus =
897 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
898 hdd_wmm_notify_app(pQosContext);
899 }
900 break;
901
902 case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
903 /* invalid params -- notify the application */
904 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
905 /* this was triggered by an application */
906 pQosContext->lastStatus =
907 HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
908 hdd_wmm_notify_app(pQosContext);
909 }
910 break;
911
912 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING:
913 /* nothing to do for now. when APSD is established we'll have work to do */
914 break;
915
916 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700917 hdd_err("Modify successful but U-APSD failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800918
919 /* QoS modification was successful but setting U=APSD
920 * failed. This will always be an explicit QoS
921 * instance, so all we can do is notify the
922 * application and let it clean up.
923 */
924 if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
925 /* this was triggered by an application */
926 pQosContext->lastStatus =
927 HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED;
928 hdd_wmm_notify_app(pQosContext);
929 }
930 /* Since U-APSD portion failed disabled trigger frame
931 * generation
932 */
933 hdd_wmm_disable_tl_uapsd(pQosContext);
934
935 break;
936
937 case SME_QOS_STATUS_HANDING_OFF:
938 /* no roaming so we won't see this */
939 break;
940
941 case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND:
942 /* need to tell TL to stop trigger frame generation */
943 hdd_wmm_disable_tl_uapsd(pQosContext);
944 break;
945
946 case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND:
947 /* need to tell TL to start sending trigger frames again */
948 hdd_wmm_enable_tl_uapsd(pQosContext);
949 break;
950
951 default:
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700952 hdd_err("unexpected SME Status=%d", smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530953 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800954 }
955
956 /* if Tspec only allows downstream traffic then access is not
957 * allowed
958 */
959 if (pAc->wmmAcTspecValid &&
960 (pAc->wmmAcTspecInfo.ts_info.direction ==
961 SME_QOS_WMM_TS_DIR_DOWNLINK)) {
962 pAc->wmmAcAccessAllowed = false;
963 }
964 /* if we have valid Tpsec or if ACM bit is not set, allow access */
965 if ((pAc->wmmAcTspecValid &&
966 (pAc->wmmAcTspecInfo.ts_info.direction !=
967 SME_QOS_WMM_TS_DIR_DOWNLINK)) || !pAc->wmmAcAccessRequired) {
968 pAc->wmmAcAccessAllowed = true;
969 }
970
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700971 hdd_notice("complete, access for TL AC %d is%sallowed",
972 acType, pAc->wmmAcAccessAllowed ? " " : " not ");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800973
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530974 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800975}
976#endif
977
978/**
979 * hdd_wmmps_helper() - Function to set uapsd psb dynamically
980 *
981 * @pAdapter: [in] pointer to adapter structure
982 * @ptr: [in] pointer to command buffer
983 *
984 * Return: Zero on success, appropriate error on failure.
985 */
986int hdd_wmmps_helper(hdd_adapter_t *pAdapter, uint8_t *ptr)
987{
988 if (NULL == pAdapter) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700989 hdd_err("pAdapter is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800990 return -EINVAL;
991 }
992 if (NULL == ptr) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -0700993 hdd_err("ptr is NULL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994 return -EINVAL;
995 }
996 /* convert ASCII to integer */
997 pAdapter->configuredPsb = ptr[9] - '0';
998 pAdapter->psbChanged = HDD_PSB_CHANGED;
999
1000 return 0;
1001}
1002
1003/**
1004 * __hdd_wmm_do_implicit_qos() - Function which will attempt to setup
1005 * QoS for any AC requiring it.
1006 * @work: [in] pointer to work structure.
1007 *
1008 * Return: none
1009 */
1010static void __hdd_wmm_do_implicit_qos(struct work_struct *work)
1011{
1012 hdd_wmm_qos_context_t *pQosContext =
1013 container_of(work, hdd_wmm_qos_context_t, wmmAcSetupImplicitQos);
1014 hdd_adapter_t *pAdapter;
1015 sme_ac_enum_type acType;
1016 hdd_wmm_ac_status_t *pAc;
1017#ifndef WLAN_MDM_CODE_REDUCTION_OPT
1018 sme_QosStatusType smeStatus;
1019#endif
1020 sme_QosWmmTspecInfo qosInfo;
1021 hdd_context_t *hdd_ctx;
1022
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001023 hdd_info("Entered, context %p", pQosContext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001024
1025 if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic)) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001026 hdd_err("Invalid QoS Context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 return;
1028 }
1029
1030 pAdapter = pQosContext->pAdapter;
1031
1032 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301033 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001034 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001035
1036 acType = pQosContext->acType;
1037 pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1038
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001039 hdd_info("pAdapter %p acType %d", pAdapter, acType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001040
1041 if (!pAc->wmmAcAccessNeeded) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001042 hdd_err("AC %d doesn't need service", acType);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001043 pQosContext->magic = 0;
1044 kfree(pQosContext);
1045 return;
1046 }
1047
1048 pAc->wmmAcAccessPending = true;
1049 pAc->wmmAcAccessNeeded = false;
1050
1051 memset(&qosInfo, 0, sizeof(qosInfo));
1052
1053 qosInfo.ts_info.psb = pAdapter->configuredPsb;
1054
1055 switch (acType) {
1056 case SME_AC_VO:
1057 qosInfo.ts_info.up = SME_QOS_WMM_UP_VO;
1058 /* Check if there is any valid configuration from framework */
1059 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1060 qosInfo.ts_info.psb =
1061 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1062 UapsdMask & SME_QOS_UAPSD_VO) ? 1 : 0;
1063 }
1064 qosInfo.ts_info.direction =
1065 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVo;
1066 qosInfo.ts_info.tid = 255;
1067 qosInfo.mean_data_rate =
1068 (WLAN_HDD_GET_CTX(pAdapter))->config->
1069 InfraMeanDataRateAcVo;
1070 qosInfo.min_phy_rate =
1071 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVo;
1072 qosInfo.min_service_interval =
1073 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSrvIntv;
1074 qosInfo.nominal_msdu_size =
1075 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVo;
1076 qosInfo.surplus_bw_allowance =
1077 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVo;
1078 qosInfo.suspension_interval =
1079 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSuspIntv;
1080 break;
1081 case SME_AC_VI:
1082 qosInfo.ts_info.up = SME_QOS_WMM_UP_VI;
1083 /* Check if there is any valid configuration from framework */
1084 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1085 qosInfo.ts_info.psb =
1086 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1087 UapsdMask & SME_QOS_UAPSD_VI) ? 1 : 0;
1088 }
1089 qosInfo.ts_info.direction =
1090 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVi;
1091 qosInfo.ts_info.tid = 255;
1092 qosInfo.mean_data_rate =
1093 (WLAN_HDD_GET_CTX(pAdapter))->config->
1094 InfraMeanDataRateAcVi;
1095 qosInfo.min_phy_rate =
1096 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVi;
1097 qosInfo.min_service_interval =
1098 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSrvIntv;
1099 qosInfo.nominal_msdu_size =
1100 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVi;
1101 qosInfo.surplus_bw_allowance =
1102 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVi;
1103 qosInfo.suspension_interval =
1104 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSuspIntv;
1105 break;
1106 default:
1107 case SME_AC_BE:
1108 qosInfo.ts_info.up = SME_QOS_WMM_UP_BE;
1109 /* Check if there is any valid configuration from framework */
1110 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1111 qosInfo.ts_info.psb =
1112 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1113 UapsdMask & SME_QOS_UAPSD_BE) ? 1 : 0;
1114 }
1115 qosInfo.ts_info.direction =
1116 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBe;
1117 qosInfo.ts_info.tid = 255;
1118 qosInfo.mean_data_rate =
1119 (WLAN_HDD_GET_CTX(pAdapter))->config->
1120 InfraMeanDataRateAcBe;
1121 qosInfo.min_phy_rate =
1122 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBe;
1123 qosInfo.min_service_interval =
1124 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSrvIntv;
1125 qosInfo.nominal_msdu_size =
1126 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBe;
1127 qosInfo.surplus_bw_allowance =
1128 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBe;
1129 qosInfo.suspension_interval =
1130 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSuspIntv;
1131 break;
1132 case SME_AC_BK:
1133 qosInfo.ts_info.up = SME_QOS_WMM_UP_BK;
1134 /* Check if there is any valid configuration from framework */
1135 if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) {
1136 qosInfo.ts_info.psb =
1137 ((WLAN_HDD_GET_CTX(pAdapter))->config->
1138 UapsdMask & SME_QOS_UAPSD_BK) ? 1 : 0;
1139 }
1140 qosInfo.ts_info.direction =
1141 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBk;
1142 qosInfo.ts_info.tid = 255;
1143 qosInfo.mean_data_rate =
1144 (WLAN_HDD_GET_CTX(pAdapter))->config->
1145 InfraMeanDataRateAcBk;
1146 qosInfo.min_phy_rate =
1147 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBk;
1148 qosInfo.min_service_interval =
1149 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSrvIntv;
1150 qosInfo.nominal_msdu_size =
1151 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBk;
1152 qosInfo.surplus_bw_allowance =
1153 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBk;
1154 qosInfo.suspension_interval =
1155 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSuspIntv;
1156 break;
1157 }
1158#ifdef FEATURE_WLAN_ESE
1159 qosInfo.inactivity_interval =
1160 (WLAN_HDD_GET_CTX(pAdapter))->config->InfraInactivityInterval;
1161#endif
1162 qosInfo.ts_info.burst_size_defn =
1163 (WLAN_HDD_GET_CTX(pAdapter))->config->burstSizeDefinition;
1164
1165 switch ((WLAN_HDD_GET_CTX(pAdapter))->config->tsInfoAckPolicy) {
1166 case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK:
1167 qosInfo.ts_info.ack_policy =
1168 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1169 break;
1170
1171 case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK:
1172 qosInfo.ts_info.ack_policy =
1173 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK;
1174 break;
1175
1176 default:
1177 /* unknown */
1178 qosInfo.ts_info.ack_policy =
1179 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1180 }
1181
1182 if (qosInfo.ts_info.ack_policy ==
1183 SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) {
1184 if (!sme_qos_is_ts_info_ack_policy_valid
1185 ((tpAniSirGlobal) WLAN_HDD_GET_HAL_CTX(pAdapter), &qosInfo,
1186 pAdapter->sessionId)) {
1187 qosInfo.ts_info.ack_policy =
1188 SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1189 }
1190 }
1191
1192 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
1193 list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList);
1194 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
1195
1196#ifndef WLAN_MDM_CODE_REDUCTION_OPT
1197 smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
1198 pAdapter->sessionId,
1199 &qosInfo,
1200 hdd_wmm_sme_callback,
1201 pQosContext,
1202 qosInfo.ts_info.up,
1203 &pQosContext->qosFlowId);
1204
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001205 hdd_notice("sme_qos_setup_req returned %d flowid %d",
1206 smeStatus, pQosContext->qosFlowId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001207
1208 /* need to check the return values and act appropriately */
1209 switch (smeStatus) {
1210 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
1211 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
1212 /* setup is pending, so no more work to do now. all
1213 * further work will be done in hdd_wmm_sme_callback()
1214 */
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001215 hdd_info("Setup is pending, no further work");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216
1217 break;
1218
1219 case SME_QOS_STATUS_SETUP_FAILURE_RSP:
1220 /* we can't tell the difference between when a request
1221 * fails because AP rejected it versus when SME
1222 * encountered an internal error. in either case SME
1223 * won't ever reference this context so free the
1224 * record
1225 */
1226 hdd_wmm_free_context(pQosContext);
1227
1228 /* fall through and start packets flowing */
1229 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
1230 /* no ACM in effect, no need to setup U-APSD */
1231 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
1232 /* no ACM in effect, U-APSD is desired but was already setup */
1233
1234 /* for these cases everything is already setup so we
1235 * can signal TL that it has work to do
1236 */
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001237 hdd_info("Setup is complete, notify TL");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001238
1239 pAc->wmmAcAccessAllowed = true;
1240 pAc->wmmAcAccessGranted = true;
1241 pAc->wmmAcAccessPending = false;
1242
1243 break;
1244
1245 default:
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001246 hdd_err("unexpected SME Status=%d", smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301247 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001248 }
1249#endif
1250
1251}
1252
1253/**
1254 * hdd_wmm_do_implicit_qos() - SSR wraper function for hdd_wmm_do_implicit_qos
1255 * @work: pointer to work_struct
1256 *
1257 * Return: none
1258 */
1259static void hdd_wmm_do_implicit_qos(struct work_struct *work)
1260{
1261 cds_ssr_protect(__func__);
1262 __hdd_wmm_do_implicit_qos(work);
1263 cds_ssr_unprotect(__func__);
1264}
1265
1266/**
1267 * hdd_wmm_init() - initialize the WMM DSCP configuation
1268 * @pAdapter : [in] pointer to Adapter context
1269 *
1270 * This function will initialize the WMM DSCP configuation of an
1271 * adapter to an initial state. The configuration can later be
1272 * overwritten via application APIs or via QoS Map sent OTA.
1273 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301274 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001275 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301276QDF_STATUS hdd_wmm_init(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001277{
1278 sme_QosWmmUpType *hddWmmDscpToUpMap = pAdapter->hddWmmDscpToUpMap;
1279 uint8_t dscp;
1280
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001281 hdd_info("Entered");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001282
1283 /* DSCP to User Priority Lookup Table
1284 * By default use the 3 Precedence bits of DSCP as the User Priority
1285 */
1286 for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++) {
1287 hddWmmDscpToUpMap[dscp] = dscp >> 3;
1288 }
1289
1290 /* Special case for Expedited Forwarding (DSCP 46) */
1291 hddWmmDscpToUpMap[46] = SME_QOS_WMM_UP_VO;
1292
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301293 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001294}
1295
1296/**
1297 * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter
1298 * @pAdapter: [in] pointer to Adapter context
1299 *
1300 * This function will initialize the WMM configuation and status of an
1301 * adapter to an initial state. The configuration can later be
1302 * overwritten via application APIs
1303 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301304 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001305 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301306QDF_STATUS hdd_wmm_adapter_init(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001307{
1308 hdd_wmm_ac_status_t *pAcStatus;
1309 sme_ac_enum_type acType;
1310
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001311 hdd_info("Entered");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001312
1313 pAdapter->hddWmmStatus.wmmQap = false;
1314 INIT_LIST_HEAD(&pAdapter->hddWmmStatus.wmmContextList);
1315 mutex_init(&pAdapter->hddWmmStatus.wmmLock);
1316
1317 for (acType = 0; acType < WLAN_MAX_AC; acType++) {
1318 pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1319 pAcStatus->wmmAcAccessRequired = false;
1320 pAcStatus->wmmAcAccessNeeded = false;
1321 pAcStatus->wmmAcAccessPending = false;
1322 pAcStatus->wmmAcAccessFailed = false;
1323 pAcStatus->wmmAcAccessGranted = false;
1324 pAcStatus->wmmAcAccessAllowed = false;
1325 pAcStatus->wmmAcTspecValid = false;
1326 pAcStatus->wmmAcUapsdInfoValid = false;
1327 }
1328 /* Invalid value(0xff) to indicate psb not configured through
1329 * framework initially.
1330 */
1331 pAdapter->configuredPsb = HDD_PSB_CFG_INVALID;
1332
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301333 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001334}
1335
1336/**
1337 * hdd_wmm_adapter_clear() - Function which will clear the WMM status
1338 * for all the ACs
1339 *
1340 * @pAdapter: [in] pointer to Adapter context
1341 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301342 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001343 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301344QDF_STATUS hdd_wmm_adapter_clear(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001345{
1346 hdd_wmm_ac_status_t *pAcStatus;
1347 sme_ac_enum_type acType;
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001348
1349 hdd_info("Entered");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001350 for (acType = 0; acType < WLAN_MAX_AC; acType++) {
1351 pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType];
1352 pAcStatus->wmmAcAccessRequired = false;
1353 pAcStatus->wmmAcAccessNeeded = false;
1354 pAcStatus->wmmAcAccessPending = false;
1355 pAcStatus->wmmAcAccessFailed = false;
1356 pAcStatus->wmmAcAccessGranted = false;
1357 pAcStatus->wmmAcAccessAllowed = false;
1358 pAcStatus->wmmAcTspecValid = false;
1359 pAcStatus->wmmAcUapsdInfoValid = false;
1360 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301361 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001362}
1363
1364/**
1365 * hdd_wmm_close() - WMM close function
1366 * @pAdapter: [in] pointer to adapter context
1367 *
1368 * Function which will perform any necessary work to to clean up the
1369 * WMM functionality prior to the kernel module unload.
1370 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301371 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001372 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301373QDF_STATUS hdd_wmm_adapter_close(hdd_adapter_t *pAdapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001374{
1375 hdd_wmm_qos_context_t *pQosContext;
1376
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001377 hdd_info("Entered");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001378
1379 /* free any context records that we still have linked */
1380 while (!list_empty(&pAdapter->hddWmmStatus.wmmContextList)) {
1381 pQosContext =
1382 list_first_entry(&pAdapter->hddWmmStatus.wmmContextList,
1383 hdd_wmm_qos_context_t, node);
1384#ifdef FEATURE_WLAN_ESE
1385 hdd_wmm_disable_inactivity_timer(pQosContext);
1386#endif
1387 if (pQosContext->handle == HDD_WMM_HANDLE_IMPLICIT
1388 && pQosContext->magic == HDD_WMM_CTX_MAGIC)
1389 cds_flush_work(&pQosContext->wmmAcSetupImplicitQos);
1390
1391 hdd_wmm_free_context(pQosContext);
1392 }
1393
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301394 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001395}
1396
1397/**
1398 * hdd_wmm_classify_pkt() - Function which will classify an OS packet
Govind Singhb7ab5772015-10-08 16:38:37 +05301399 * into a WMM AC based on DSCP
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001400 *
Govind Singhb7ab5772015-10-08 16:38:37 +05301401 * @adapter: adapter upon which the packet is being transmitted
1402 * @skb: pointer to network buffer
1403 * @user_pri: user priority of the OS packet
1404 * @is_eapol: eapol packet flag
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405 *
1406 * Return: None
1407 */
1408static
Govind Singhb7ab5772015-10-08 16:38:37 +05301409void hdd_wmm_classify_pkt(hdd_adapter_t *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001410 struct sk_buff *skb,
Govind Singhb7ab5772015-10-08 16:38:37 +05301411 sme_QosWmmUpType *user_pri,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001412 bool *is_eapol)
1413{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001414 unsigned char dscp;
Govind Singhb7ab5772015-10-08 16:38:37 +05301415 unsigned char tos;
1416 union generic_ethhdr *eth_hdr;
1417 struct iphdr *ip_hdr;
1418 struct ipv6hdr *ipv6hdr;
1419 unsigned char *pkt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001420
1421 /* this code is executed for every packet therefore
1422 * all debug code is kept conditional
1423 */
1424
1425#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001426 hdd_info("Entered");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001427#endif /* HDD_WMM_DEBUG */
1428
Govind Singhb7ab5772015-10-08 16:38:37 +05301429 pkt = skb->data;
1430 eth_hdr = (union generic_ethhdr *)pkt;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001431
1432#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001433 hdd_info("proto is 0x%04x", skb->protocol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001434#endif /* HDD_WMM_DEBUG */
1435
Govind Singhb7ab5772015-10-08 16:38:37 +05301436 if (eth_hdr->eth_II.h_proto == htons(ETH_P_IP)) {
1437 /* case 1: Ethernet II IP packet */
1438 ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_II)];
1439 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001440#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001441 hdd_info("Ethernet II IP Packet, tos is %d", tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001442#endif /* HDD_WMM_DEBUG */
1443
Govind Singhb7ab5772015-10-08 16:38:37 +05301444 } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) {
1445 ipv6hdr = ipv6_hdr(skb);
1446 tos = ntohs(*(const __be16 *)ipv6hdr) >> 4;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001447#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001448 hdd_info("Ethernet II IPv6 Packet, tos is %d", tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001449#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301450 } else if ((ntohs(eth_hdr->eth_II.h_proto) < WLAN_MIN_PROTO) &&
1451 (eth_hdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) &&
1452 (eth_hdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) &&
1453 (eth_hdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) &&
1454 (eth_hdr->eth_8023.h_proto == htons(ETH_P_IP))) {
1455 /* case 2: 802.3 LLC/SNAP IP packet */
1456 ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_8023)];
1457 tos = ip_hdr->tos;
1458#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001459 hdd_info("802.3 LLC/SNAP IP Packet, tos is %d", tos);
Govind Singhb7ab5772015-10-08 16:38:37 +05301460#endif /* HDD_WMM_DEBUG */
1461 } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) {
1462 /* VLAN tagged */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001463
Govind Singhb7ab5772015-10-08 16:38:37 +05301464 if (eth_hdr->eth_IIv.h_vlan_encapsulated_proto ==
1465 htons(ETH_P_IP)) {
1466 /* case 3: Ethernet II vlan-tagged IP packet */
1467 ip_hdr =
1468 (struct iphdr *)
1469 &pkt[sizeof(eth_hdr->eth_IIv)];
1470 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001471#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001472 hdd_info("Ethernet II VLAN tagged IP Packet, tos is %d",
1473 tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001474#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301475 } else
1476 if ((ntohs(eth_hdr->eth_IIv.h_vlan_encapsulated_proto)
1477 < WLAN_MIN_PROTO)
1478 && (eth_hdr->eth_8023v.h_snap.dsap ==
1479 WLAN_SNAP_DSAP)
1480 && (eth_hdr->eth_8023v.h_snap.ssap ==
1481 WLAN_SNAP_SSAP)
1482 && (eth_hdr->eth_8023v.h_snap.ctrl ==
1483 WLAN_SNAP_CTRL)
1484 && (eth_hdr->eth_8023v.h_proto ==
1485 htons(ETH_P_IP))) {
1486 /* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */
1487 ip_hdr =
1488 (struct iphdr *)
1489 &pkt[sizeof(eth_hdr->eth_8023v)];
1490 tos = ip_hdr->tos;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001491#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001492 hdd_info("802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d",
1493 tos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001494#endif /* HDD_WMM_DEBUG */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001495 } else {
1496 /* default */
1497#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001498 hdd_warn("VLAN tagged Unhandled Protocol, using default tos");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001499#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301500 tos = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001501 }
1502 } else {
1503 /* default */
1504#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001505 hdd_warn("Unhandled Protocol, using default tos");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001506#endif /* HDD_WMM_DEBUG */
Govind Singhb7ab5772015-10-08 16:38:37 +05301507 /* Give the highest priority to 802.1x packet */
1508 if (eth_hdr->eth_II.h_proto ==
1509 htons(HDD_ETHERTYPE_802_1_X)) {
1510 tos = 0xC0;
1511 *is_eapol = true;
1512 } else
1513 tos = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001514 }
1515
Govind Singhb7ab5772015-10-08 16:38:37 +05301516 dscp = (tos >> 2) & 0x3f;
1517 *user_pri = adapter->hddWmmDscpToUpMap[dscp];
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001518
1519#ifdef HDD_WMM_DEBUG
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001520 hdd_notice("tos is %d, dscp is %d, up is %d", tos, dscp, *user_pri);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001521#endif /* HDD_WMM_DEBUG */
1522
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001523 return;
1524}
1525
Jeff Johnsone54e2ae2016-07-18 17:56:20 -07001526/**
1527 * __hdd_get_queue_index() - get queue index
1528 * @up: user priority
1529 *
1530 * Return: queue_index
1531 */
1532static uint16_t __hdd_get_queue_index(uint16_t up)
1533{
1534 if (qdf_unlikely(up >= ARRAY_SIZE(hdd_linux_up_to_ac_map)))
1535 return HDD_LINUX_AC_BE;
1536 return hdd_linux_up_to_ac_map[up];
1537}
1538
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001539#ifdef QCA_LL_TX_FLOW_CONTROL_V2
1540/**
1541 * hdd_get_queue_index() - get queue index
1542 * @up: user priority
1543 * @is_eapol: is_eapol flag
1544 *
1545 * Return: queue_index
1546 */
1547static
1548uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol)
1549{
Anurag Chouhanc5548422016-02-24 18:33:27 +05301550 if (qdf_unlikely(is_eapol == true))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001551 return HDD_LINUX_AC_HI_PRIO;
Jeff Johnsone54e2ae2016-07-18 17:56:20 -07001552 return __hdd_get_queue_index(up);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001553}
1554#else
1555static
1556uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol)
1557{
Jeff Johnsone54e2ae2016-07-18 17:56:20 -07001558 return __hdd_get_queue_index(up);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001559}
1560#endif
1561
1562
1563/**
1564 * hdd_hostapd_select_queue() - Function which will classify the packet
1565 * according to linux qdisc expectation.
1566 *
1567 * @dev: [in] pointer to net_device structure
1568 * @skb: [in] pointer to os packet
1569 *
1570 * Return: Qdisc queue index
1571 */
1572uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb
1573#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
1574 , void *accel_priv
1575#endif
1576#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1577 , select_queue_fallback_t fallback
1578#endif
1579
1580)
1581{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001582 sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
1583 uint16_t queueIndex;
Govind Singhb7ab5772015-10-08 16:38:37 +05301584 hdd_adapter_t *adapter = (hdd_adapter_t *) netdev_priv(dev);
1585 hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001586 bool is_eapol = false;
Mukul Sharmab3152182015-10-30 20:47:30 +05301587 int status = 0;
Govind Singhb7ab5772015-10-08 16:38:37 +05301588 status = wlan_hdd_validate_context(hddctx);
Mukul Sharmab3152182015-10-30 20:47:30 +05301589
1590 if (status != 0) {
1591 skb->priority = SME_QOS_WMM_UP_BE;
1592 return HDD_LINUX_AC_BE;
1593 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001594
Govind Singhb7ab5772015-10-08 16:38:37 +05301595 /* Get the user priority from IP header */
1596 hdd_wmm_classify_pkt(adapter, skb, &up, &is_eapol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001597 skb->priority = up;
1598 queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
1599
1600 return queueIndex;
1601}
1602
1603/**
1604 * hdd_wmm_select_queue() - Function which will classify the packet
1605 * according to linux qdisc expectation.
1606 *
1607 * @dev: [in] pointer to net_device structure
1608 * @skb: [in] pointer to os packet
1609 *
1610 * Return: Qdisc queue index
1611 */
1612uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb)
1613{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001614 sme_QosWmmUpType up = SME_QOS_WMM_UP_BE;
1615 uint16_t queueIndex;
1616 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
1617 bool is_eapol = false;
Mukul Sharmabfd19ba2015-10-30 20:35:35 +05301618 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
1619 int status;
1620
1621 status = wlan_hdd_validate_context(hdd_ctx);
1622 if (status != 0) {
1623 skb->priority = SME_QOS_WMM_UP_BE;
1624 return HDD_LINUX_AC_BE;
1625 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001626
Govind Singhb7ab5772015-10-08 16:38:37 +05301627 /* Get the user priority from IP header */
1628 hdd_wmm_classify_pkt(pAdapter, skb, &up, &is_eapol);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629 skb->priority = up;
1630 queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
Govind Singhb7ab5772015-10-08 16:38:37 +05301631
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632 return queueIndex;
1633}
1634
1635/**
1636 * hdd_wmm_acquire_access_required() - Function which will determine
1637 * acquire admittance for a WMM AC is required or not based on psb configuration
1638 * done in framework
1639 *
1640 * @pAdapter: [in] pointer to adapter structure
1641 * @acType: [in] WMM AC type of OS packet
1642 *
1643 * Return: void
1644 */
1645void hdd_wmm_acquire_access_required(hdd_adapter_t *pAdapter,
1646 sme_ac_enum_type acType)
1647{
1648 /* Each bit in the LSB nibble indicates 1 AC.
1649 * Clearing the particular bit in LSB nibble to indicate
1650 * access required
1651 */
1652 switch (acType) {
1653 case SME_AC_BK:
1654 /* clear first bit */
1655 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK;
1656 break;
1657 case SME_AC_BE:
1658 /* clear second bit */
1659 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK;
1660 break;
1661 case SME_AC_VI:
1662 /* clear third bit */
1663 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK;
1664 break;
1665 case SME_AC_VO:
1666 /* clear fourth bit */
1667 pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK;
1668 break;
1669 default:
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001670 hdd_err("Invalid AC Type");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001671 break;
1672 }
1673}
1674
1675/**
1676 * hdd_wmm_acquire_access() - Function which will attempt to acquire
1677 * admittance for a WMM AC
1678 *
1679 * @pAdapter: [in] pointer to adapter context
1680 * @acType: [in] WMM AC type of OS packet
1681 * @pGranted: [out] pointer to bool flag when indicates if access
1682 * has been granted or not
1683 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301684 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001685 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301686QDF_STATUS hdd_wmm_acquire_access(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001687 sme_ac_enum_type acType, bool *pGranted)
1688{
1689 hdd_wmm_qos_context_t *pQosContext;
1690
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001691 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001692 "%s: Entered for AC %d", __func__, acType);
1693
1694 if (!hdd_wmm_is_active(pAdapter) ||
1695 !(WLAN_HDD_GET_CTX(pAdapter))->config->bImplicitQosEnabled ||
1696 !pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessRequired) {
1697 /* either we don't want QoS or the AP doesn't support
1698 * QoS or we don't want to do implicit QoS
1699 */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001700 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001701 "%s: QoS not configured on both ends ", __func__);
1702
1703 *pGranted =
1704 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1705 wmmAcAccessAllowed;
1706
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301707 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001708 }
1709 /* do we already have an implicit QoS request pending for this AC? */
1710 if ((pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded) ||
1711 (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessPending)) {
1712 /* request already pending so we need to wait for that
1713 * response
1714 */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001715 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001716 "%s: Implicit QoS for TL AC %d already scheduled",
1717 __func__, acType);
1718
1719 *pGranted = false;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301720 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001721 }
1722 /* did we already fail to establish implicit QoS for this AC?
1723 * (if so, access should have been granted when the failure
1724 * was handled)
1725 */
1726 if (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessFailed) {
1727 /* request previously failed
1728 * allow access, but we'll be downgraded
1729 */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001730 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001731 "%s: Implicit QoS for TL AC %d previously failed",
1732 __func__, acType);
1733
1734 if (!pAdapter->hddWmmStatus.wmmAcStatus[acType].
1735 wmmAcAccessRequired) {
1736 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1737 wmmAcAccessAllowed = true;
1738 *pGranted = true;
1739 } else {
1740 pAdapter->hddWmmStatus.wmmAcStatus[acType].
1741 wmmAcAccessAllowed = false;
1742 *pGranted = false;
1743 }
1744
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301745 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001746 }
1747 /* we need to establish implicit QoS */
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001748 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749 "%s: Need to schedule implicit QoS for TL AC %d, pAdapter is %p",
1750 __func__, acType, pAdapter);
1751
1752 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded = true;
1753
1754 pQosContext = kmalloc(sizeof(*pQosContext), GFP_ATOMIC);
1755 if (NULL == pQosContext) {
1756 /* no memory for QoS context. Nothing we can do but
1757 * let data flow
1758 */
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001759 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760 "%s: Unable to allocate context", __func__);
1761 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed =
1762 true;
1763 *pGranted = true;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301764 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001765 }
1766
1767 pQosContext->acType = acType;
1768 pQosContext->pAdapter = pAdapter;
1769 pQosContext->qosFlowId = 0;
1770 pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT;
1771 pQosContext->magic = HDD_WMM_CTX_MAGIC;
1772 pQosContext->is_inactivity_timer_running = false;
1773
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001774 INIT_WORK(&pQosContext->wmmAcSetupImplicitQos, hdd_wmm_do_implicit_qos);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775
Rajeev Kumar3d4b1ef2016-01-29 15:57:26 -08001776 QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001777 "%s: Scheduling work for AC %d, context %p",
1778 __func__, acType, pQosContext);
1779
1780 schedule_work(&pQosContext->wmmAcSetupImplicitQos);
1781
1782 /* caller will need to wait until the work takes place and
1783 * TSPEC negotiation completes
1784 */
1785 *pGranted = false;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301786 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001787}
1788
1789/**
1790 * hdd_wmm_assoc() - Function which will handle the housekeeping
1791 * required by WMM when association takes place
1792 *
1793 * @pAdapter: [in] pointer to adapter context
1794 * @pRoamInfo: [in] pointer to roam information
1795 * @eBssType: [in] type of BSS
1796 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301797 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301799QDF_STATUS hdd_wmm_assoc(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001800 tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType)
1801{
1802 uint8_t uapsdMask;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301803 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001804 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1805
1806 /* when we associate we need to notify TL if it needs to
1807 * enable UAPSD for any access categories
1808 */
1809
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001810 hdd_info("Entered");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001811
1812 if (pRoamInfo->fReassocReq) {
1813 /* when we reassociate we should continue to use
1814 * whatever parameters were previously established.
1815 * if we are reassociating due to a U-APSD change for
1816 * a particular Access Category, then the change will
1817 * be communicated to HDD via the QoS callback
1818 * associated with the given flow, and U-APSD
1819 * parameters will be updated there
1820 */
1821
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001822 hdd_info("Reassoc so no work, Exiting");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001823
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301824 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001825 }
1826 /* get the negotiated UAPSD Mask */
1827 uapsdMask =
1828 pRoamInfo->u.pConnectedProfile->modifyProfileFields.uapsd_mask;
1829
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001830 hdd_info("U-APSD mask is 0x%02x", (int)uapsdMask);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001831
1832 if (uapsdMask & HDD_AC_VO) {
1833 status =
1834 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1835 pcds_context,
1836 (WLAN_HDD_GET_STATION_CTX_PTR
1837 (pAdapter))->conn_info.staId[0],
1838 SME_AC_VO, 7, 7,
1839 pHddCtx->config->InfraUapsdVoSrvIntv,
1840 pHddCtx->config->InfraUapsdVoSuspIntv,
1841 SME_BI_DIR, 1,
1842 pAdapter->sessionId,
1843 pHddCtx->config->DelayedTriggerFrmInt);
1844
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301845 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846 }
1847
1848 if (uapsdMask & HDD_AC_VI) {
1849 status =
1850 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1851 pcds_context,
1852 (WLAN_HDD_GET_STATION_CTX_PTR
1853 (pAdapter))->conn_info.staId[0],
1854 SME_AC_VI, 5, 5,
1855 pHddCtx->config->InfraUapsdViSrvIntv,
1856 pHddCtx->config->InfraUapsdViSuspIntv,
1857 SME_BI_DIR, 1,
1858 pAdapter->sessionId,
1859 pHddCtx->config->DelayedTriggerFrmInt);
1860
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301861 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001862 }
1863
1864 if (uapsdMask & HDD_AC_BK) {
1865 status =
1866 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1867 pcds_context,
1868 (WLAN_HDD_GET_STATION_CTX_PTR
1869 (pAdapter))->conn_info.staId[0],
1870 SME_AC_BK, 2, 2,
1871 pHddCtx->config->InfraUapsdBkSrvIntv,
1872 pHddCtx->config->InfraUapsdBkSuspIntv,
1873 SME_BI_DIR, 1,
1874 pAdapter->sessionId,
1875 pHddCtx->config->DelayedTriggerFrmInt);
1876
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301877 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001878 }
1879
1880 if (uapsdMask & HDD_AC_BE) {
1881 status =
1882 sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->
1883 pcds_context,
1884 (WLAN_HDD_GET_STATION_CTX_PTR
1885 (pAdapter))->conn_info.staId[0],
1886 SME_AC_BE, 3, 3,
1887 pHddCtx->config->InfraUapsdBeSrvIntv,
1888 pHddCtx->config->InfraUapsdBeSuspIntv,
1889 SME_BI_DIR, 1,
1890 pAdapter->sessionId,
1891 pHddCtx->config->DelayedTriggerFrmInt);
1892
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301893 QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001894 }
1895
1896 status = sme_update_dsc_pto_up_mapping(pHddCtx->hHal,
1897 pAdapter->hddWmmDscpToUpMap,
1898 pAdapter->sessionId);
1899
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301900 if (!QDF_IS_STATUS_SUCCESS(status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001901 hdd_wmm_init(pAdapter);
1902 }
1903
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001904 hdd_info("Exiting");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001905
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301906 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001907}
1908
1909static const uint8_t acm_mask_bit[WLAN_MAX_AC] = {
1910 0x4, /* SME_AC_BK */
1911 0x8, /* SME_AC_BE */
1912 0x2, /* SME_AC_VI */
1913 0x1 /* SME_AC_VO */
1914};
1915
1916/**
1917 * hdd_wmm_connect() - Function which will handle the housekeeping
1918 * required by WMM when a connection is established
1919 *
1920 * @pAdapter : [in] pointer to adapter context
1921 * @pRoamInfo: [in] pointer to roam information
1922 * @eBssType : [in] type of BSS
1923 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301924 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001925 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301926QDF_STATUS hdd_wmm_connect(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001927 tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType)
1928{
1929 int ac;
1930 bool qap;
1931 bool qosConnection;
1932 uint8_t acmMask;
1933
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001934 hdd_info("Entered");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001935
1936 if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) &&
1937 pRoamInfo && pRoamInfo->u.pConnectedProfile) {
1938 qap = pRoamInfo->u.pConnectedProfile->qap;
1939 qosConnection = pRoamInfo->u.pConnectedProfile->qosConnection;
1940 acmMask = pRoamInfo->u.pConnectedProfile->acm_mask;
1941 } else {
1942 qap = true;
1943 qosConnection = true;
1944 acmMask = 0x0;
1945 }
1946
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001947 hdd_info("qap is %d, qosConnection is %d, acmMask is 0x%x",
1948 qap, qosConnection, acmMask);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001949
1950 pAdapter->hddWmmStatus.wmmQap = qap;
1951 pAdapter->hddWmmStatus.wmmQosConnection = qosConnection;
1952
1953 for (ac = 0; ac < WLAN_MAX_AC; ac++) {
1954 if (qap && qosConnection && (acmMask & acm_mask_bit[ac])) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001955 hdd_info("ac %d on", ac);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001956
1957 /* admission is required */
1958 pAdapter->hddWmmStatus.wmmAcStatus[ac].
1959 wmmAcAccessRequired = true;
1960 pAdapter->hddWmmStatus.wmmAcStatus[ac].
1961 wmmAcAccessAllowed = false;
1962 pAdapter->hddWmmStatus.wmmAcStatus[ac].
1963 wmmAcAccessGranted = false;
1964 /* after reassoc if we have valid tspec, allow access */
1965 if (pAdapter->hddWmmStatus.wmmAcStatus[ac].
1966 wmmAcTspecValid
1967 && (pAdapter->hddWmmStatus.wmmAcStatus[ac].
1968 wmmAcTspecInfo.ts_info.direction !=
1969 SME_QOS_WMM_TS_DIR_DOWNLINK)) {
1970 pAdapter->hddWmmStatus.wmmAcStatus[ac].
1971 wmmAcAccessAllowed = true;
1972 }
1973 } else {
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001974 hdd_info("ac %d off", ac);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001975 /* admission is not required so access is allowed */
1976 pAdapter->hddWmmStatus.wmmAcStatus[ac].
1977 wmmAcAccessRequired = false;
1978 pAdapter->hddWmmStatus.wmmAcStatus[ac].
1979 wmmAcAccessAllowed = true;
1980 }
1981
1982 }
1983
Jeff Johnson5ae20e92016-08-19 13:51:48 -07001984 hdd_info("Exiting");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001985
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301986 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001987}
1988
1989/**
1990 * hdd_wmm_get_uapsd_mask() - Function which will calculate the
1991 * initial value of the UAPSD mask based upon the device configuration
1992 *
1993 * @pAdapter : [in] pointer to adapter context
1994 * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored
1995 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301996 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001997 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301998QDF_STATUS hdd_wmm_get_uapsd_mask(hdd_adapter_t *pAdapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001999 uint8_t *pUapsdMask)
2000{
2001 uint8_t uapsdMask;
2002
2003 if (HDD_WMM_USER_MODE_NO_QOS ==
2004 (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) {
2005 /* no QOS then no UAPSD */
2006 uapsdMask = 0;
2007 } else {
2008 /* start with the default mask */
2009 uapsdMask = (WLAN_HDD_GET_CTX(pAdapter))->config->UapsdMask;
2010
2011 /* disable UAPSD for any ACs with a 0 Service Interval */
2012 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2013 InfraUapsdVoSrvIntv == 0) {
2014 uapsdMask &= ~HDD_AC_VO;
2015 }
2016
2017 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2018 InfraUapsdViSrvIntv == 0) {
2019 uapsdMask &= ~HDD_AC_VI;
2020 }
2021
2022 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2023 InfraUapsdBkSrvIntv == 0) {
2024 uapsdMask &= ~HDD_AC_BK;
2025 }
2026
2027 if ((WLAN_HDD_GET_CTX(pAdapter))->config->
2028 InfraUapsdBeSrvIntv == 0) {
2029 uapsdMask &= ~HDD_AC_BE;
2030 }
2031 }
2032
2033 /* return calculated mask */
2034 *pUapsdMask = uapsdMask;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302035 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002036}
2037
2038/**
2039 * hdd_wmm_is_active() - Function which will determine if WMM is
2040 * active on the current connection
2041 *
2042 * @pAdapter: [in] pointer to adapter context
2043 *
2044 * Return: true if WMM is enabled, false if WMM is not enabled
2045 */
2046bool hdd_wmm_is_active(hdd_adapter_t *pAdapter)
2047{
2048 if ((!pAdapter->hddWmmStatus.wmmQosConnection) ||
2049 (!pAdapter->hddWmmStatus.wmmQap)) {
2050 return false;
2051 } else {
2052 return true;
2053 }
2054}
2055
2056/**
2057 * hdd_wmm_addts() - Function which will add a traffic spec at the
2058 * request of an application
2059 *
2060 * @pAdapter : [in] pointer to adapter context
2061 * @handle : [in] handle to uniquely identify a TS
2062 * @pTspec : [in] pointer to the traffic spec
2063 *
2064 * Return: HDD_WLAN_WMM_STATUS_*
2065 */
2066hdd_wlan_wmm_status_e hdd_wmm_addts(hdd_adapter_t *pAdapter,
2067 uint32_t handle,
2068 sme_QosWmmTspecInfo *pTspec)
2069{
2070 hdd_wmm_qos_context_t *pQosContext;
2071 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2072#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2073 sme_QosStatusType smeStatus;
2074#endif
2075 bool found = false;
2076
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002077 hdd_info("Entered with handle 0x%x", handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002078
2079 /* see if a context already exists with the given handle */
2080 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2081 list_for_each_entry(pQosContext,
2082 &pAdapter->hddWmmStatus.wmmContextList, node) {
2083 if (pQosContext->handle == handle) {
2084 found = true;
2085 break;
2086 }
2087 }
2088 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2089 if (found) {
2090 /* record with that handle already exists */
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002091 hdd_err("Record already exists with handle 0x%x", handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002092
2093 /* Application is trying to modify some of the Tspec
2094 * params. Allow it
2095 */
2096 smeStatus = sme_qos_modify_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
2097 pTspec, pQosContext->qosFlowId);
2098
2099 /* need to check the return value and act appropriately */
2100 switch (smeStatus) {
2101 case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
2102 status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING;
2103 break;
2104 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2105 status =
2106 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
2107 break;
2108 case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
2109 status =
2110 HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
2111 break;
2112 case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
2113 status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
2114 break;
2115 case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
2116 status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2117 break;
2118 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2119 status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2120 break;
2121 default:
2122 /* we didn't get back one of the
2123 * SME_QOS_STATUS_MODIFY_* status codes
2124 */
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002125 hdd_err("unexpected SME Status=%d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002126 smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302127 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002128 return HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2129 }
2130
2131 /* we were successful, save the status */
2132 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2133 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2134 pQosContext->lastStatus = status;
2135 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2136
2137 return status;
2138 }
2139
2140 pQosContext = kmalloc(sizeof(*pQosContext), GFP_KERNEL);
2141 if (NULL == pQosContext) {
2142 /* no memory for QoS context. Nothing we can do */
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002143 hdd_err("Unable to allocate QoS context");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002144 return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE;
2145 }
2146 /* we assume the tspec has already been validated by the caller */
2147
2148 pQosContext->handle = handle;
2149 if (pTspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE)
2150 pQosContext->acType = hdd_wmm_up_to_ac_map[pTspec->ts_info.up];
2151 else {
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002152 hdd_err("ts_info.up (%d) larger than max value (%d), use default acType (%d)",
2153 pTspec->ts_info.up,
2154 HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002155 pQosContext->acType = hdd_wmm_up_to_ac_map[0];
2156 }
2157 pQosContext->pAdapter = pAdapter;
2158 pQosContext->qosFlowId = 0;
2159 pQosContext->magic = HDD_WMM_CTX_MAGIC;
2160
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002161 hdd_notice("Setting up QoS, context %p", pQosContext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002162
2163 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2164 list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList);
2165 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2166
2167#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2168 smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter),
2169 pAdapter->sessionId,
2170 pTspec,
2171 hdd_wmm_sme_callback,
2172 pQosContext,
2173 pTspec->ts_info.up,
2174 &pQosContext->qosFlowId);
2175
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002176 hdd_notice("sme_qos_setup_req returned %d flowid %d",
2177 smeStatus, pQosContext->qosFlowId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002178
2179 /* need to check the return value and act appropriately */
2180 switch (smeStatus) {
2181 case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
2182 status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2183 break;
2184 case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2185 status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
2186 break;
2187 case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
2188 status =
2189 HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
2190 break;
2191 case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
2192 status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2193 break;
2194 case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
2195 hdd_wmm_free_context(pQosContext);
2196 return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
2197 case SME_QOS_STATUS_SETUP_FAILURE_RSP:
2198 /* we can't tell the difference between when a request
2199 * fails because AP rejected it versus when SME
2200 * encounterd an internal error
2201 */
2202 hdd_wmm_free_context(pQosContext);
2203 return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2204 case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2205 hdd_wmm_free_context(pQosContext);
2206 return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2207 default:
2208 /* we didn't get back one of the
2209 * SME_QOS_STATUS_SETUP_* status codes
2210 */
2211 hdd_wmm_free_context(pQosContext);
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002212 hdd_err("unexpected SME Status=%d", smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302213 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002214 return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2215 }
2216#endif
2217
2218 /* we were successful, save the status */
2219 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2220 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2221 pQosContext->lastStatus = status;
2222 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2223
2224 return status;
2225}
2226
2227/**
2228 * hdd_wmm_delts() - Function which will delete a traffic spec at the
2229 * request of an application
2230 *
2231 * @pAdapter: [in] pointer to adapter context
2232 * @handle: [in] handle to uniquely identify a TS
2233 *
2234 * Return: HDD_WLAN_WMM_STATUS_*
2235 */
2236hdd_wlan_wmm_status_e hdd_wmm_delts(hdd_adapter_t *pAdapter, uint32_t handle)
2237{
2238 hdd_wmm_qos_context_t *pQosContext;
2239 bool found = false;
2240 sme_ac_enum_type acType = 0;
2241 uint32_t qosFlowId = 0;
2242 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2243#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2244 sme_QosStatusType smeStatus;
2245#endif
2246
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002247 hdd_info("Entered with handle 0x%x", handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002248
2249 /* locate the context with the given handle */
2250 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2251 list_for_each_entry(pQosContext,
2252 &pAdapter->hddWmmStatus.wmmContextList, node) {
2253 if (pQosContext->handle == handle) {
2254 found = true;
2255 acType = pQosContext->acType;
2256 qosFlowId = pQosContext->qosFlowId;
2257 break;
2258 }
2259 }
2260 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2261
2262 if (false == found) {
2263 /* we didn't find the handle */
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002264 hdd_info("handle 0x%x not found", handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002265 return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2266 }
2267
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002268 hdd_info("found handle 0x%x, flow %d, AC %d, context %p",
2269 handle, qosFlowId, acType, pQosContext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002270
2271#ifndef WLAN_MDM_CODE_REDUCTION_OPT
2272 smeStatus =
2273 sme_qos_release_req(WLAN_HDD_GET_HAL_CTX(pAdapter), qosFlowId);
2274
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002275 hdd_info("SME flow %d released, SME status %d", qosFlowId, smeStatus);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002276
2277 switch (smeStatus) {
2278 case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
2279 /* this flow is the only one on that AC, so go ahead
2280 * and update our TSPEC state for the AC
2281 */
2282 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcTspecValid =
2283 false;
Sreelakshmi Konamki9d6b75d2016-02-10 12:17:23 +05302284 pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed =
2285 false;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002286
2287 /* need to tell TL to stop trigger timer, etc */
2288 hdd_wmm_disable_tl_uapsd(pQosContext);
2289
2290#ifdef FEATURE_WLAN_ESE
2291 /* disable the inactivity timer */
2292 hdd_wmm_disable_inactivity_timer(pQosContext);
2293#endif
2294 /* we are done with this context */
2295 hdd_wmm_free_context(pQosContext);
2296
2297 /* SME must not fire any more callbacks for this flow
2298 * since the context is no longer valid
2299 */
2300
2301 return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
2302
2303 case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
2304 /* do nothing as we will get a response from SME */
2305 status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING;
2306 break;
2307
2308 case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
2309 /* nothing we can do with the existing flow except leave it */
2310 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2311 break;
2312
2313 case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
2314 /* nothing we can do with the existing flow except leave it */
2315 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2316
2317 default:
2318 /* we didn't get back one of the
2319 * SME_QOS_STATUS_RELEASE_* status codes
2320 */
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002321 hdd_err("unexpected SME Status=%d", smeStatus);
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05302322 QDF_ASSERT(0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002323 status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2324 }
2325
2326#endif
2327 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2328 if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2329 pQosContext->lastStatus = status;
2330 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2331
2332 return status;
2333}
2334
2335/**
2336 * hdd_wmm_checkts() - Function which will return the status of a traffic
2337 * spec at the request of an application
2338 *
2339 * @pAdapter: [in] pointer to adapter context
2340 * @handle: [in] handle to uniquely identify a TS
2341 *
2342 * Return: HDD_WLAN_WMM_STATUS_*
2343 */
2344hdd_wlan_wmm_status_e hdd_wmm_checkts(hdd_adapter_t *pAdapter, uint32_t handle)
2345{
2346 hdd_wmm_qos_context_t *pQosContext;
2347 hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST;
2348
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002349 hdd_info("Entered with handle 0x%x", handle);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002350
2351 /* locate the context with the given handle */
2352 mutex_lock(&pAdapter->hddWmmStatus.wmmLock);
2353 list_for_each_entry(pQosContext,
2354 &pAdapter->hddWmmStatus.wmmContextList, node) {
2355 if (pQosContext->handle == handle) {
Jeff Johnson5ae20e92016-08-19 13:51:48 -07002356 hdd_info("found handle 0x%x, context %p",
2357 handle, pQosContext);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002358
2359 status = pQosContext->lastStatus;
2360 break;
2361 }
2362 }
2363 mutex_unlock(&pAdapter->hddWmmStatus.wmmLock);
2364 return status;
2365}