xref: /wlan-dirver/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c (revision 99923a8330d524fd331c8d65ac1e713b4b8086f9)
1 /*
2  * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: HDD WMM
21  *
22  * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation)
23  * houses all the logic for WMM in HDD.
24  *
25  * On the control path, it has the logic to setup QoS, modify QoS and delete
26  * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an
27  * explicit application invoked and an internal HDD invoked.  The implicit QoS
28  * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but
29  * which DO mark their traffic for priortization. It also has logic to start,
30  * update and stop the U-APSD trigger frame generation. It also has logic to
31  * read WMM related config parameters from the registry.
32  *
33  * On the data path, it has the logic to figure out the WMM AC of an egress
34  * packet and when to signal TL to serve a particular AC queue. It also has the
35  * logic to retrieve a packet based on WMM priority in response to a fetch from
36  * TL.
37  *
38  * The remaining functions are utility functions for information hiding.
39  */
40 
41 /* Include files */
42 #include <linux/netdevice.h>
43 #include <linux/skbuff.h>
44 #include <linux/etherdevice.h>
45 #include <linux/if_vlan.h>
46 #include <linux/ip.h>
47 #include <linux/semaphore.h>
48 #include <linux/ipv6.h>
49 #include <wlan_hdd_tx_rx.h>
50 #include <wlan_hdd_wmm.h>
51 #include <wlan_hdd_ether.h>
52 #include <wlan_hdd_hostapd.h>
53 #include <wlan_hdd_softap_tx_rx.h>
54 #include <cds_sched.h>
55 #include "sme_api.h"
56 
57 #define WLAN_HDD_MAX_DSCP 0x3f
58 
59 #define HDD_WMM_UP_TO_AC_MAP_SIZE 8
60 
61 const uint8_t hdd_wmm_up_to_ac_map[] = {
62 	SME_AC_BE,
63 	SME_AC_BK,
64 	SME_AC_BK,
65 	SME_AC_BE,
66 	SME_AC_VI,
67 	SME_AC_VI,
68 	SME_AC_VO,
69 	SME_AC_VO
70 };
71 
72 /**
73  * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to
74  * operate on different traffic.
75  */
76 #ifdef QCA_LL_TX_FLOW_CONTROL_V2
77 void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter)
78 {
79 	/* Enable HI_PRIO queue */
80 	netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VO);
81 	netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VI);
82 	netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BE);
83 	netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BK);
84 	netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO);
85 
86 }
87 #else
88 void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter)
89 {
90 }
91 #endif
92 
93 /* Linux based UP -> AC Mapping */
94 const uint8_t hdd_linux_up_to_ac_map[HDD_WMM_UP_TO_AC_MAP_SIZE] = {
95 	HDD_LINUX_AC_BE,
96 	HDD_LINUX_AC_BK,
97 	HDD_LINUX_AC_BK,
98 	HDD_LINUX_AC_BE,
99 	HDD_LINUX_AC_VI,
100 	HDD_LINUX_AC_VI,
101 	HDD_LINUX_AC_VO,
102 	HDD_LINUX_AC_VO
103 };
104 
105 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
106 /**
107  * hdd_wmm_enable_tl_uapsd() - function which decides whether and
108  * how to update UAPSD parameters in TL
109  *
110  * @pQosContext: [in] the pointer the QoS instance control block
111  *
112  * Return: None
113  */
114 static void hdd_wmm_enable_tl_uapsd(struct hdd_wmm_qos_context *pQosContext)
115 {
116 	struct hdd_adapter *adapter = pQosContext->adapter;
117 	sme_ac_enum_type acType = pQosContext->acType;
118 	struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType];
119 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
120 	QDF_STATUS status;
121 	uint32_t service_interval;
122 	uint32_t suspension_interval;
123 	enum sme_qos_wmm_dir_type direction;
124 	bool psb;
125 
126 	/* The TSPEC must be valid */
127 	if (pAc->wmmAcTspecValid == false) {
128 		hdd_err("Invoked with invalid TSPEC");
129 		return;
130 	}
131 	/* determine the service interval */
132 	if (pAc->wmmAcTspecInfo.min_service_interval) {
133 		service_interval = pAc->wmmAcTspecInfo.min_service_interval;
134 	} else if (pAc->wmmAcTspecInfo.max_service_interval) {
135 		service_interval = pAc->wmmAcTspecInfo.max_service_interval;
136 	} else {
137 		/* no service interval is present in the TSPEC */
138 		/* this is OK, there just won't be U-APSD */
139 		hdd_debug("No service interval supplied");
140 		service_interval = 0;
141 	}
142 
143 	/* determine the suspension interval & direction */
144 	suspension_interval = pAc->wmmAcTspecInfo.suspension_interval;
145 	direction = pAc->wmmAcTspecInfo.ts_info.direction;
146 	psb = pAc->wmmAcTspecInfo.ts_info.psb;
147 
148 	/* if we have previously enabled U-APSD, have any params changed? */
149 	if ((pAc->wmmAcUapsdInfoValid) &&
150 	    (pAc->wmmAcUapsdServiceInterval == service_interval) &&
151 	    (pAc->wmmAcUapsdSuspensionInterval == suspension_interval) &&
152 	    (pAc->wmmAcUapsdDirection == direction) &&
153 	    (pAc->wmmAcIsUapsdEnabled == psb)) {
154 		hdd_debug("No change in U-APSD parameters");
155 		return;
156 	}
157 	/* everything is in place to notify TL */
158 	status =
159 		sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR(adapter))->
160 					   conn_info.staId[0], acType,
161 					   pAc->wmmAcTspecInfo.ts_info.tid,
162 					   pAc->wmmAcTspecInfo.ts_info.up,
163 					   service_interval, suspension_interval,
164 					   direction, psb, adapter->session_id,
165 					   hdd_ctx->config->DelayedTriggerFrmInt);
166 
167 	if (!QDF_IS_STATUS_SUCCESS(status)) {
168 		hdd_err("Failed to enable U-APSD for AC=%d", acType);
169 		return;
170 	}
171 	/* stash away the parameters that were used */
172 	pAc->wmmAcUapsdInfoValid = true;
173 	pAc->wmmAcUapsdServiceInterval = service_interval;
174 	pAc->wmmAcUapsdSuspensionInterval = suspension_interval;
175 	pAc->wmmAcUapsdDirection = direction;
176 	pAc->wmmAcIsUapsdEnabled = psb;
177 
178 	hdd_debug("Enabled UAPSD in TL srv_int=%d susp_int=%d dir=%d AC=%d",
179 		   service_interval, suspension_interval, direction, acType);
180 
181 }
182 
183 /**
184  * hdd_wmm_disable_tl_uapsd() - function which decides whether
185  * to disable UAPSD parameters in TL
186  *
187  * @pQosContext: [in] the pointer the QoS instance control block
188  *
189  * Return: None
190  */
191 static void hdd_wmm_disable_tl_uapsd(struct hdd_wmm_qos_context *pQosContext)
192 {
193 	struct hdd_adapter *adapter = pQosContext->adapter;
194 	sme_ac_enum_type acType = pQosContext->acType;
195 	struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType];
196 	QDF_STATUS status;
197 
198 	/* have we previously enabled UAPSD? */
199 	if (pAc->wmmAcUapsdInfoValid == true) {
200 		status =
201 			sme_disable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR
202 							     (adapter))->conn_info.staId[0],
203 						    acType, adapter->session_id);
204 
205 		if (!QDF_IS_STATUS_SUCCESS(status)) {
206 			hdd_err("Failed to disable U-APSD for AC=%d", acType);
207 		} else {
208 			/* TL no longer has valid UAPSD info */
209 			pAc->wmmAcUapsdInfoValid = false;
210 			hdd_debug("Disabled UAPSD in TL for AC=%d", acType);
211 		}
212 	}
213 }
214 
215 #endif
216 
217 /**
218  * hdd_wmm_free_context() - function which frees a QoS context
219  *
220  * @pQosContext: [in] the pointer the QoS instance control block
221  *
222  * Return: None
223  */
224 static void hdd_wmm_free_context(struct hdd_wmm_qos_context *pQosContext)
225 {
226 	struct hdd_adapter *adapter;
227 
228 	hdd_debug("Entered, context %pK", pQosContext);
229 
230 	if (unlikely((NULL == pQosContext) ||
231 		     (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
232 		/* must have been freed in another thread */
233 		return;
234 	}
235 	/* get pointer to the adapter context */
236 	adapter = pQosContext->adapter;
237 
238 	/* take the wmmLock since we're manipulating the context list */
239 	mutex_lock(&adapter->hdd_wmm_status.wmmLock);
240 
241 	/* make sure nobody thinks this is a valid context */
242 	pQosContext->magic = 0;
243 
244 	/* unlink the context */
245 	list_del(&pQosContext->node);
246 
247 	/* done manipulating the list */
248 	mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
249 
250 	/* reclaim memory */
251 	qdf_mem_free(pQosContext);
252 
253 }
254 
255 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
256 /**
257  * hdd_wmm_notify_app() - function which notifies an application
258  *			  of changes in state of it flow
259  *
260  * @pQosContext: [in] the pointer the QoS instance control block
261  *
262  * Return: None
263  */
264 #define MAX_NOTIFY_LEN 50
265 static void hdd_wmm_notify_app(struct hdd_wmm_qos_context *pQosContext)
266 {
267 	struct hdd_adapter *adapter;
268 	union iwreq_data wrqu;
269 	char buf[MAX_NOTIFY_LEN + 1];
270 
271 	hdd_debug("Entered, context %pK", pQosContext);
272 
273 	if (unlikely((NULL == pQosContext) ||
274 		     (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
275 		hdd_err("Invalid QoS Context");
276 		return;
277 	}
278 
279 	/* create the event */
280 	memset(&wrqu, 0, sizeof(wrqu));
281 	memset(buf, 0, sizeof(buf));
282 
283 	snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]",
284 		 (unsigned int)pQosContext->handle,
285 		 (unsigned int)pQosContext->lastStatus);
286 
287 	wrqu.data.pointer = buf;
288 	wrqu.data.length = strlen(buf);
289 
290 	/* get pointer to the adapter */
291 	adapter = pQosContext->adapter;
292 
293 	/* send the event */
294 	hdd_debug("Sending [%s]", buf);
295 	wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf);
296 }
297 
298 #ifdef FEATURE_WLAN_ESE
299 /**
300  * hdd_wmm_inactivity_timer_cb() - inactivity timer callback function
301  *
302  * @user_data: opaque user data registered with the timer.  In the
303  * case of this timer, the associated wmm QoS context is registered.
304  *
305  * This timer handler function is called for every inactivity interval
306  * per AC. This function gets the current transmitted packets on the
307  * given AC, and checks if there was any TX activity from the previous
308  * interval. If there was no traffic then it would delete the TS that
309  * was negotiated on that AC.
310  *
311  * Return: None
312  */
313 static void hdd_wmm_inactivity_timer_cb(void *user_data)
314 {
315 	struct hdd_wmm_qos_context *pQosContext = user_data;
316 	struct hdd_adapter *adapter;
317 	struct hdd_wmm_ac_status *pAc;
318 	hdd_wlan_wmm_status_e status;
319 	QDF_STATUS qdf_status;
320 	uint32_t currentTrafficCnt = 0;
321 	sme_ac_enum_type acType;
322 
323 	if (!pQosContext) {
324 		hdd_err("invalid user data");
325 		return;
326 	}
327 	acType = pQosContext->acType;
328 
329 	adapter = pQosContext->adapter;
330 	if ((NULL == adapter) ||
331 	    (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
332 		hdd_err("invalid adapter: %pK", adapter);
333 		return;
334 	}
335 
336 	pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType];
337 
338 	/* Get the Tx stats for this AC. */
339 	currentTrafficCnt =
340 		adapter->hdd_stats.tx_rx_stats.tx_classified_ac[pQosContext->
341 								    acType];
342 
343 	hdd_warn("WMM inactivity Timer for AC=%d, currentCnt=%d, prevCnt=%d",
344 		 acType, (int)currentTrafficCnt, (int)pAc->wmmPrevTrafficCnt);
345 	if (pAc->wmmPrevTrafficCnt == currentTrafficCnt) {
346 		/* there is no traffic activity, delete the TSPEC for this AC */
347 		status = hdd_wmm_delts(adapter, pQosContext->handle);
348 		hdd_warn("Deleted TS on AC %d, due to inactivity with status = %d!!!",
349 			 acType, status);
350 	} else {
351 		pAc->wmmPrevTrafficCnt = currentTrafficCnt;
352 		if (pAc->wmmInactivityTimer.state == QDF_TIMER_STATE_STOPPED) {
353 			/* Restart the timer */
354 			qdf_status =
355 				qdf_mc_timer_start(&pAc->wmmInactivityTimer,
356 						   pAc->wmmInactivityTime);
357 			if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
358 				hdd_err("Restarting inactivity timer failed on AC %d",
359 					acType);
360 			}
361 		} else {
362 			QDF_ASSERT(qdf_mc_timer_get_current_state
363 					   (&pAc->wmmInactivityTimer) ==
364 				   QDF_TIMER_STATE_STOPPED);
365 		}
366 	}
367 }
368 
369 /**
370  * hdd_wmm_enable_inactivity_timer() -
371  *	function to enable the traffic inactivity timer for the given AC
372  *
373  * @pQosContext: [in] pointer to pQosContext
374  * @inactivityTime: [in] value of the inactivity interval in millisecs
375  *
376  * When a QoS-Tspec is successfully setup, if the inactivity interval
377  * time specified in the AddTS parameters is non-zero, this function
378  * is invoked to start a traffic inactivity timer for the given AC.
379  *
380  * Return: QDF_STATUS enumeration
381  */
382 static QDF_STATUS
383 hdd_wmm_enable_inactivity_timer(struct hdd_wmm_qos_context *pQosContext,
384 				uint32_t inactivityTime)
385 {
386 	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
387 	struct hdd_adapter *adapter = pQosContext->adapter;
388 	sme_ac_enum_type acType = pQosContext->acType;
389 	struct hdd_wmm_ac_status *pAc;
390 
391 	adapter = pQosContext->adapter;
392 	pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType];
393 
394 	qdf_status = qdf_mc_timer_init(&pAc->wmmInactivityTimer,
395 				       QDF_TIMER_TYPE_SW,
396 				       hdd_wmm_inactivity_timer_cb,
397 				       pQosContext);
398 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
399 		hdd_err("Initializing inactivity timer failed on AC %d",
400 			  acType);
401 		return qdf_status;
402 	}
403 	/* Start the inactivity timer */
404 	qdf_status = qdf_mc_timer_start(&pAc->wmmInactivityTimer,
405 					inactivityTime);
406 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
407 		hdd_err("Starting inactivity timer failed on AC %d",
408 			  acType);
409 		qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer);
410 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
411 			hdd_err("Failed to destroy inactivity timer");
412 
413 		return qdf_status;
414 	}
415 	pAc->wmmInactivityTime = inactivityTime;
416 	/* Initialize the current tx traffic count on this AC */
417 	pAc->wmmPrevTrafficCnt =
418 		adapter->hdd_stats.tx_rx_stats.tx_classified_ac[pQosContext->
419 								    acType];
420 	pQosContext->is_inactivity_timer_running = true;
421 	return qdf_status;
422 }
423 
424 /**
425  * hdd_wmm_disable_inactivity_timer() -
426  *	function to disable the traffic inactivity timer for the given AC.
427  *
428  * @pQosContext: [in] pointer to pQosContext
429  *
430  * This function is invoked to disable the traffic inactivity timer
431  * for the given AC.  This is normally done when the TS is deleted.
432  *
433  * Return: QDF_STATUS enumeration
434  */
435 static QDF_STATUS
436 hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context *pQosContext)
437 {
438 	struct hdd_adapter *adapter = pQosContext->adapter;
439 	sme_ac_enum_type acType = pQosContext->acType;
440 	struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType];
441 	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
442 
443 	/* Clear the timer and the counter */
444 	pAc->wmmInactivityTime = 0;
445 	pAc->wmmPrevTrafficCnt = 0;
446 
447 	if (pQosContext->is_inactivity_timer_running == true) {
448 		pQosContext->is_inactivity_timer_running = false;
449 		qdf_status = qdf_mc_timer_stop(&pAc->wmmInactivityTimer);
450 		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
451 			hdd_err("Failed to stop inactivity timer");
452 			return qdf_status;
453 		}
454 		qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer);
455 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
456 			hdd_err("Failed to destroy inactivity timer:Timer started");
457 	}
458 
459 	return qdf_status;
460 }
461 #else
462 
463 static QDF_STATUS
464 hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context *pQosContext)
465 {
466 	return QDF_STATUS_SUCCESS;
467 }
468 #endif /* FEATURE_WLAN_ESE */
469 
470 /**
471  * hdd_wmm_sme_callback() - callback for QoS notifications
472  *
473  * @mac_handle: [in] the MAC handle
474  * @context : [in] the HDD callback context
475  * @pCurrentQosInfo : [in] the TSPEC params
476  * @smeStatus : [in] the QoS related SME status
477  * @qosFlowId: [in] the unique identifier of the flow
478  *
479  * This callback is registered by HDD with SME for receiving QoS
480  * notifications. Even though this function has a static scope it
481  * gets called externally through some function pointer magic (so
482  * there is a need for rigorous parameter checking).
483  *
484  * Return: QDF_STATUS enumeration
485  */
486 static QDF_STATUS hdd_wmm_sme_callback(mac_handle_t mac_handle,
487 			void *context,
488 			struct sme_qos_wmmtspecinfo *pCurrentQosInfo,
489 			enum sme_qos_statustype smeStatus,
490 			uint32_t qosFlowId)
491 {
492 	struct hdd_wmm_qos_context *pQosContext = context;
493 	struct hdd_adapter *adapter;
494 	sme_ac_enum_type acType;
495 	struct hdd_wmm_ac_status *pAc;
496 
497 	hdd_debug("Entered, context %pK", pQosContext);
498 
499 	if (unlikely((NULL == pQosContext) ||
500 		     (HDD_WMM_CTX_MAGIC != pQosContext->magic))) {
501 		hdd_err("Invalid QoS Context");
502 		return QDF_STATUS_E_FAILURE;
503 	}
504 
505 	adapter = pQosContext->adapter;
506 	acType = pQosContext->acType;
507 	pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType];
508 
509 	hdd_debug("status %d flowid %d info %pK",
510 		 smeStatus, qosFlowId, pCurrentQosInfo);
511 
512 	switch (smeStatus) {
513 
514 	case SME_QOS_STATUS_SETUP_SUCCESS_IND:
515 		hdd_debug("Setup is complete");
516 
517 		/* there will always be a TSPEC returned with this
518 		 * status, even if a TSPEC is not exchanged OTA
519 		 */
520 		if (pCurrentQosInfo) {
521 			pAc->wmmAcTspecValid = true;
522 			memcpy(&pAc->wmmAcTspecInfo,
523 			       pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
524 		}
525 		pAc->wmmAcAccessAllowed = true;
526 		pAc->wmmAcAccessGranted = true;
527 		pAc->wmmAcAccessPending = false;
528 		pAc->wmmAcAccessFailed = false;
529 
530 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
531 
532 			hdd_debug("Explicit Qos, notifying user space");
533 
534 			/* this was triggered by an application */
535 			pQosContext->lastStatus =
536 				HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
537 			hdd_wmm_notify_app(pQosContext);
538 		}
539 
540 #ifdef FEATURE_WLAN_ESE
541 		/* Check if the inactivity interval is specified */
542 		if (pCurrentQosInfo && pCurrentQosInfo->inactivity_interval) {
543 			hdd_debug("Inactivity timer value = %d for AC=%d",
544 				  pCurrentQosInfo->inactivity_interval, acType);
545 			hdd_wmm_enable_inactivity_timer(pQosContext,
546 							pCurrentQosInfo->
547 							inactivity_interval);
548 		}
549 #endif /* FEATURE_WLAN_ESE */
550 
551 		/* notify TL to enable trigger frames if necessary */
552 		hdd_wmm_enable_tl_uapsd(pQosContext);
553 
554 		break;
555 
556 	case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
557 		hdd_debug("Setup is complete (U-APSD set previously)");
558 
559 		pAc->wmmAcAccessAllowed = true;
560 		pAc->wmmAcAccessGranted = true;
561 		pAc->wmmAcAccessPending = false;
562 
563 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
564 
565 			hdd_debug("Explicit Qos, notifying user space");
566 
567 			/* this was triggered by an application */
568 			pQosContext->lastStatus =
569 				HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
570 			hdd_wmm_notify_app(pQosContext);
571 		}
572 
573 		break;
574 
575 	case SME_QOS_STATUS_SETUP_FAILURE_RSP:
576 		hdd_err("Setup failed");
577 		/* QoS setup failed */
578 
579 		pAc->wmmAcAccessPending = false;
580 		pAc->wmmAcAccessFailed = true;
581 		pAc->wmmAcAccessAllowed = false;
582 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
583 
584 			hdd_debug("Explicit Qos, notifying user space");
585 
586 			/* this was triggered by an application */
587 			pQosContext->lastStatus =
588 				HDD_WLAN_WMM_STATUS_SETUP_FAILED;
589 
590 			hdd_wmm_notify_app(pQosContext);
591 		}
592 
593 		/* disable the inactivity timer */
594 		hdd_wmm_disable_inactivity_timer(pQosContext);
595 
596 		/* Setting up QoS Failed, QoS context can be released.
597 		 * SME is releasing this flow information and if HDD
598 		 * doesn't release this context, next time if
599 		 * application uses the same handle to set-up QoS, HDD
600 		 * (as it has QoS context for this handle) will issue
601 		 * Modify QoS request to SME but SME will reject as now
602 		 * it has no information for this flow.
603 		 */
604 		hdd_wmm_free_context(pQosContext);
605 		break;
606 
607 	case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
608 		hdd_err("Setup Invalid Params, notify TL");
609 		/* QoS setup failed */
610 		pAc->wmmAcAccessAllowed = false;
611 
612 		if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
613 
614 			/* we note the failure, but we also mark
615 			 * access as allowed so that the packets will
616 			 * flow.  Note that the MAC will "do the right
617 			 * thing"
618 			 */
619 			pAc->wmmAcAccessPending = false;
620 			pAc->wmmAcAccessFailed = true;
621 			pAc->wmmAcAccessAllowed = true;
622 
623 		} else {
624 			hdd_debug("Explicit Qos, notifying user space");
625 
626 			/* this was triggered by an application */
627 			pQosContext->lastStatus =
628 				HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
629 			hdd_wmm_notify_app(pQosContext);
630 		}
631 		break;
632 
633 	case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
634 		hdd_err("Setup failed, not a QoS AP");
635 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
636 			hdd_info("Explicit Qos, notifying user space");
637 
638 			/* this was triggered by an application */
639 			pQosContext->lastStatus =
640 				HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
641 			hdd_wmm_notify_app(pQosContext);
642 		}
643 		break;
644 
645 	case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
646 		hdd_debug("Setup pending");
647 		/* not a callback status -- ignore if we get it */
648 		break;
649 
650 	case SME_QOS_STATUS_SETUP_MODIFIED_IND:
651 		hdd_debug("Setup modified");
652 		if (pCurrentQosInfo) {
653 			/* update the TSPEC */
654 			pAc->wmmAcTspecValid = true;
655 			memcpy(&pAc->wmmAcTspecInfo,
656 			       pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
657 
658 			if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
659 				hdd_debug("Explicit Qos, notifying user space");
660 
661 				/* this was triggered by an application */
662 				pQosContext->lastStatus =
663 					HDD_WLAN_WMM_STATUS_MODIFIED;
664 				hdd_wmm_notify_app(pQosContext);
665 			}
666 			/* need to tell TL to update its UAPSD handling */
667 			hdd_wmm_enable_tl_uapsd(pQosContext);
668 		}
669 		break;
670 
671 	case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
672 		if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
673 
674 			/* this was triggered by implicit QoS so we
675 			 * know packets are pending
676 			 */
677 			pAc->wmmAcAccessPending = false;
678 			pAc->wmmAcAccessGranted = true;
679 			pAc->wmmAcAccessAllowed = true;
680 
681 		} else {
682 			hdd_debug("Explicit Qos, notifying user space");
683 
684 			/* this was triggered by an application */
685 			pQosContext->lastStatus =
686 				HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
687 			hdd_wmm_notify_app(pQosContext);
688 		}
689 		break;
690 
691 	case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
692 		/* nothing to do for now */
693 		break;
694 
695 	case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED:
696 		hdd_err("Setup successful but U-APSD failed");
697 
698 		if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
699 
700 			/* QoS setup was successful but setting U=APSD
701 			 * failed.  Since the OTA part of the request
702 			 * was successful, we don't mark this as a
703 			 * failure.  the packets will flow.  Note that
704 			 * the MAC will "do the right thing"
705 			 */
706 			pAc->wmmAcAccessGranted = true;
707 			pAc->wmmAcAccessAllowed = true;
708 			pAc->wmmAcAccessFailed = false;
709 			pAc->wmmAcAccessPending = false;
710 
711 		} else {
712 			hdd_info("Explicit Qos, notifying user space");
713 
714 			/* this was triggered by an application */
715 			pQosContext->lastStatus =
716 				HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED;
717 			hdd_wmm_notify_app(pQosContext);
718 		}
719 
720 		/* Since U-APSD portion failed disabled trigger frame
721 		 * generation
722 		 */
723 		hdd_wmm_disable_tl_uapsd(pQosContext);
724 
725 		break;
726 
727 	case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
728 		hdd_debug("Release is complete");
729 
730 		if (pCurrentQosInfo) {
731 			hdd_debug("flows still active");
732 
733 			/* there is still at least one flow active for
734 			 * this AC so update the AC state
735 			 */
736 			memcpy(&pAc->wmmAcTspecInfo,
737 			       pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
738 
739 			/* need to tell TL to update its UAPSD handling */
740 			hdd_wmm_enable_tl_uapsd(pQosContext);
741 		} else {
742 			hdd_debug("last flow");
743 
744 			/* this is the last flow active for this AC so
745 			 * update the AC state
746 			 */
747 			pAc->wmmAcTspecValid = false;
748 
749 			/* DELTS is successful, do not allow */
750 			pAc->wmmAcAccessAllowed = false;
751 
752 			/* need to tell TL to update its UAPSD handling */
753 			hdd_wmm_disable_tl_uapsd(pQosContext);
754 		}
755 
756 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
757 			hdd_debug("Explicit Qos, notifying user space");
758 
759 			/* this was triggered by an application */
760 			pQosContext->lastStatus =
761 				HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
762 			hdd_wmm_notify_app(pQosContext);
763 		}
764 		/* disable the inactivity timer */
765 		hdd_wmm_disable_inactivity_timer(pQosContext);
766 
767 		/* we are done with this flow */
768 		hdd_wmm_free_context(pQosContext);
769 		break;
770 
771 	case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
772 		hdd_debug("Release failure");
773 
774 		/* we don't need to update our state or TL since
775 		 * nothing has changed
776 		 */
777 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
778 			hdd_debug("Explicit Qos, notifying user space");
779 
780 			/* this was triggered by an application */
781 			pQosContext->lastStatus =
782 				HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
783 			hdd_wmm_notify_app(pQosContext);
784 		}
785 
786 		break;
787 
788 	case SME_QOS_STATUS_RELEASE_QOS_LOST_IND:
789 		hdd_debug("QOS Lost indication received");
790 
791 		/* current TSPEC is no longer valid */
792 		pAc->wmmAcTspecValid = false;
793 		/* AP has sent DELTS, do not allow */
794 		pAc->wmmAcAccessAllowed = false;
795 
796 		/* need to tell TL to update its UAPSD handling */
797 		hdd_wmm_disable_tl_uapsd(pQosContext);
798 
799 		if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) {
800 			/* we no longer have implicit access granted */
801 			pAc->wmmAcAccessGranted = false;
802 			pAc->wmmAcAccessFailed = false;
803 		} else {
804 			hdd_debug("Explicit Qos, notifying user space");
805 
806 			/* this was triggered by an application */
807 			pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_LOST;
808 			hdd_wmm_notify_app(pQosContext);
809 		}
810 
811 		/* disable the inactivity timer */
812 		hdd_wmm_disable_inactivity_timer(pQosContext);
813 
814 		/* we are done with this flow */
815 		hdd_wmm_free_context(pQosContext);
816 		break;
817 
818 	case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
819 		hdd_debug("Release pending");
820 		/* not a callback status -- ignore if we get it */
821 		break;
822 
823 	case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
824 		hdd_err("Release Invalid Params");
825 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
826 			/* this was triggered by an application */
827 			pQosContext->lastStatus =
828 				HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
829 			hdd_wmm_notify_app(pQosContext);
830 		}
831 		break;
832 
833 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND:
834 		hdd_debug("Modification is complete, notify TL");
835 
836 		/* there will always be a TSPEC returned with this
837 		 * status, even if a TSPEC is not exchanged OTA
838 		 */
839 		if (pCurrentQosInfo) {
840 			pAc->wmmAcTspecValid = true;
841 			memcpy(&pAc->wmmAcTspecInfo,
842 			       pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo));
843 		}
844 
845 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
846 			/* this was triggered by an application */
847 			pQosContext->lastStatus =
848 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS;
849 			hdd_wmm_notify_app(pQosContext);
850 		}
851 		/* notify TL to enable trigger frames if necessary */
852 		hdd_wmm_enable_tl_uapsd(pQosContext);
853 
854 		break;
855 
856 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
857 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
858 			/* this was triggered by an application */
859 			pQosContext->lastStatus =
860 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
861 			hdd_wmm_notify_app(pQosContext);
862 		}
863 		break;
864 
865 	case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
866 		/* the flow modification failed so we'll leave in
867 		 * place whatever existed beforehand
868 		 */
869 
870 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
871 			/* this was triggered by an application */
872 			pQosContext->lastStatus =
873 				HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
874 			hdd_wmm_notify_app(pQosContext);
875 		}
876 		break;
877 
878 	case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
879 		hdd_debug("modification pending");
880 		/* not a callback status -- ignore if we get it */
881 		break;
882 
883 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
884 		/* the flow modification was successful but no QoS
885 		 * changes required
886 		 */
887 
888 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
889 			/* this was triggered by an application */
890 			pQosContext->lastStatus =
891 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
892 			hdd_wmm_notify_app(pQosContext);
893 		}
894 		break;
895 
896 	case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
897 		/* invalid params -- notify the application */
898 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
899 			/* this was triggered by an application */
900 			pQosContext->lastStatus =
901 				HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
902 			hdd_wmm_notify_app(pQosContext);
903 		}
904 		break;
905 
906 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING:
907 		/* nothing to do for now.  when APSD is established we'll have work to do */
908 		break;
909 
910 	case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED:
911 		hdd_err("Modify successful but U-APSD failed");
912 
913 		/* QoS modification was successful but setting U=APSD
914 		 * failed.  This will always be an explicit QoS
915 		 * instance, so all we can do is notify the
916 		 * application and let it clean up.
917 		 */
918 		if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) {
919 			/* this was triggered by an application */
920 			pQosContext->lastStatus =
921 				HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED;
922 			hdd_wmm_notify_app(pQosContext);
923 		}
924 		/* Since U-APSD portion failed disabled trigger frame
925 		 * generation
926 		 */
927 		hdd_wmm_disable_tl_uapsd(pQosContext);
928 
929 		break;
930 
931 	case SME_QOS_STATUS_HANDING_OFF:
932 		/* no roaming so we won't see this */
933 		break;
934 
935 	case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND:
936 		/* need to tell TL to stop trigger frame generation */
937 		hdd_wmm_disable_tl_uapsd(pQosContext);
938 		break;
939 
940 	case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND:
941 		/* need to tell TL to start sending trigger frames again */
942 		hdd_wmm_enable_tl_uapsd(pQosContext);
943 		break;
944 
945 	default:
946 		hdd_err("unexpected SME Status=%d", smeStatus);
947 		QDF_ASSERT(0);
948 	}
949 
950 	/* if Tspec only allows downstream traffic then access is not
951 	 * allowed
952 	 */
953 	if (pAc->wmmAcTspecValid &&
954 	    (pAc->wmmAcTspecInfo.ts_info.direction ==
955 	     SME_QOS_WMM_TS_DIR_DOWNLINK)) {
956 		pAc->wmmAcAccessAllowed = false;
957 	}
958 	/* if we have valid Tpsec or if ACM bit is not set, allow access */
959 	if ((pAc->wmmAcTspecValid &&
960 	     (pAc->wmmAcTspecInfo.ts_info.direction !=
961 	      SME_QOS_WMM_TS_DIR_DOWNLINK)) || !pAc->wmmAcAccessRequired) {
962 		pAc->wmmAcAccessAllowed = true;
963 	}
964 
965 	hdd_debug("complete, access for TL AC %d is%sallowed",
966 		   acType, pAc->wmmAcAccessAllowed ? " " : " not ");
967 
968 	return QDF_STATUS_SUCCESS;
969 }
970 #endif
971 
972 /**
973  * hdd_wmmps_helper() - Function to set uapsd psb dynamically
974  *
975  * @adapter: [in] pointer to adapter structure
976  * @ptr: [in] pointer to command buffer
977  *
978  * Return: Zero on success, appropriate error on failure.
979  */
980 int hdd_wmmps_helper(struct hdd_adapter *adapter, uint8_t *ptr)
981 {
982 	if (NULL == adapter) {
983 		hdd_err("adapter is NULL");
984 		return -EINVAL;
985 	}
986 	if (NULL == ptr) {
987 		hdd_err("ptr is NULL");
988 		return -EINVAL;
989 	}
990 	/* convert ASCII to integer */
991 	adapter->configured_psb = ptr[9] - '0';
992 	adapter->psb_changed = HDD_PSB_CHANGED;
993 
994 	return 0;
995 }
996 
997 /**
998  * __hdd_wmm_do_implicit_qos() - Function which will attempt to setup
999  *				QoS for any AC requiring it.
1000  * @work: [in] pointer to work structure.
1001  *
1002  * Return: none
1003  */
1004 static void __hdd_wmm_do_implicit_qos(struct work_struct *work)
1005 {
1006 	struct hdd_wmm_qos_context *pQosContext =
1007 		container_of(work, struct hdd_wmm_qos_context,
1008 			     wmmAcSetupImplicitQos);
1009 	struct hdd_adapter *adapter;
1010 	sme_ac_enum_type acType;
1011 	struct hdd_wmm_ac_status *pAc;
1012 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
1013 	enum sme_qos_statustype smeStatus;
1014 #endif
1015 	struct sme_qos_wmmtspecinfo qosInfo;
1016 	struct hdd_context *hdd_ctx;
1017 	mac_handle_t mac_handle;
1018 
1019 	hdd_debug("Entered, context %pK", pQosContext);
1020 
1021 	if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic)) {
1022 		hdd_err("Invalid QoS Context");
1023 		return;
1024 	}
1025 
1026 	adapter = pQosContext->adapter;
1027 
1028 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1029 	if (wlan_hdd_validate_context(hdd_ctx))
1030 		return;
1031 
1032 	mac_handle = hdd_ctx->mac_handle;
1033 
1034 	acType = pQosContext->acType;
1035 	pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType];
1036 
1037 	hdd_debug("adapter %pK acType %d", adapter, acType);
1038 
1039 	if (!pAc->wmmAcAccessNeeded) {
1040 		hdd_err("AC %d doesn't need service", acType);
1041 		pQosContext->magic = 0;
1042 		qdf_mem_free(pQosContext);
1043 		return;
1044 	}
1045 
1046 	pAc->wmmAcAccessPending = true;
1047 	pAc->wmmAcAccessNeeded = false;
1048 
1049 	memset(&qosInfo, 0, sizeof(qosInfo));
1050 
1051 	qosInfo.ts_info.psb = adapter->configured_psb;
1052 
1053 	switch (acType) {
1054 	case SME_AC_VO:
1055 		qosInfo.ts_info.up = SME_QOS_WMM_UP_VO;
1056 		/* Check if there is any valid configuration from framework */
1057 		if (HDD_PSB_CFG_INVALID == adapter->configured_psb) {
1058 			qosInfo.ts_info.psb =
1059 				((WLAN_HDD_GET_CTX(adapter))->config->
1060 				 UapsdMask & SME_QOS_UAPSD_VO) ? 1 : 0;
1061 		}
1062 		qosInfo.ts_info.direction =
1063 			(WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcVo;
1064 		qosInfo.ts_info.tid = 255;
1065 		qosInfo.mean_data_rate =
1066 			(WLAN_HDD_GET_CTX(adapter))->config->
1067 			InfraMeanDataRateAcVo;
1068 		qosInfo.min_phy_rate =
1069 			(WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcVo;
1070 		qosInfo.min_service_interval =
1071 			(WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdVoSrvIntv;
1072 		qosInfo.nominal_msdu_size =
1073 			(WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcVo;
1074 		qosInfo.surplus_bw_allowance =
1075 			(WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcVo;
1076 		qosInfo.suspension_interval =
1077 			(WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdVoSuspIntv;
1078 		break;
1079 	case SME_AC_VI:
1080 		qosInfo.ts_info.up = SME_QOS_WMM_UP_VI;
1081 		/* Check if there is any valid configuration from framework */
1082 		if (HDD_PSB_CFG_INVALID == adapter->configured_psb) {
1083 			qosInfo.ts_info.psb =
1084 				((WLAN_HDD_GET_CTX(adapter))->config->
1085 				 UapsdMask & SME_QOS_UAPSD_VI) ? 1 : 0;
1086 		}
1087 		qosInfo.ts_info.direction =
1088 			(WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcVi;
1089 		qosInfo.ts_info.tid = 255;
1090 		qosInfo.mean_data_rate =
1091 			(WLAN_HDD_GET_CTX(adapter))->config->
1092 			InfraMeanDataRateAcVi;
1093 		qosInfo.min_phy_rate =
1094 			(WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcVi;
1095 		qosInfo.min_service_interval =
1096 			(WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdViSrvIntv;
1097 		qosInfo.nominal_msdu_size =
1098 			(WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcVi;
1099 		qosInfo.surplus_bw_allowance =
1100 			(WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcVi;
1101 		qosInfo.suspension_interval =
1102 			(WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdViSuspIntv;
1103 		break;
1104 	default:
1105 	case SME_AC_BE:
1106 		qosInfo.ts_info.up = SME_QOS_WMM_UP_BE;
1107 		/* Check if there is any valid configuration from framework */
1108 		if (HDD_PSB_CFG_INVALID == adapter->configured_psb) {
1109 			qosInfo.ts_info.psb =
1110 				((WLAN_HDD_GET_CTX(adapter))->config->
1111 				 UapsdMask & SME_QOS_UAPSD_BE) ? 1 : 0;
1112 		}
1113 		qosInfo.ts_info.direction =
1114 			(WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcBe;
1115 		qosInfo.ts_info.tid = 255;
1116 		qosInfo.mean_data_rate =
1117 			(WLAN_HDD_GET_CTX(adapter))->config->
1118 			InfraMeanDataRateAcBe;
1119 		qosInfo.min_phy_rate =
1120 			(WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcBe;
1121 		qosInfo.min_service_interval =
1122 			(WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBeSrvIntv;
1123 		qosInfo.nominal_msdu_size =
1124 			(WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcBe;
1125 		qosInfo.surplus_bw_allowance =
1126 			(WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcBe;
1127 		qosInfo.suspension_interval =
1128 			(WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBeSuspIntv;
1129 		break;
1130 	case SME_AC_BK:
1131 		qosInfo.ts_info.up = SME_QOS_WMM_UP_BK;
1132 		/* Check if there is any valid configuration from framework */
1133 		if (HDD_PSB_CFG_INVALID == adapter->configured_psb) {
1134 			qosInfo.ts_info.psb =
1135 				((WLAN_HDD_GET_CTX(adapter))->config->
1136 				 UapsdMask & SME_QOS_UAPSD_BK) ? 1 : 0;
1137 		}
1138 		qosInfo.ts_info.direction =
1139 			(WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcBk;
1140 		qosInfo.ts_info.tid = 255;
1141 		qosInfo.mean_data_rate =
1142 			(WLAN_HDD_GET_CTX(adapter))->config->
1143 			InfraMeanDataRateAcBk;
1144 		qosInfo.min_phy_rate =
1145 			(WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcBk;
1146 		qosInfo.min_service_interval =
1147 			(WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBkSrvIntv;
1148 		qosInfo.nominal_msdu_size =
1149 			(WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcBk;
1150 		qosInfo.surplus_bw_allowance =
1151 			(WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcBk;
1152 		qosInfo.suspension_interval =
1153 			(WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBkSuspIntv;
1154 		break;
1155 	}
1156 #ifdef FEATURE_WLAN_ESE
1157 	qosInfo.inactivity_interval =
1158 		(WLAN_HDD_GET_CTX(adapter))->config->InfraInactivityInterval;
1159 #endif
1160 	qosInfo.ts_info.burst_size_defn =
1161 		(WLAN_HDD_GET_CTX(adapter))->config->burstSizeDefinition;
1162 
1163 	switch ((WLAN_HDD_GET_CTX(adapter))->config->tsInfoAckPolicy) {
1164 	case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK:
1165 		qosInfo.ts_info.ack_policy =
1166 			SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1167 		break;
1168 
1169 	case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK:
1170 		qosInfo.ts_info.ack_policy =
1171 			SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK;
1172 		break;
1173 
1174 	default:
1175 		/* unknown */
1176 		qosInfo.ts_info.ack_policy =
1177 			SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1178 	}
1179 
1180 	if (qosInfo.ts_info.ack_policy ==
1181 	    SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) {
1182 		if (!sme_qos_is_ts_info_ack_policy_valid
1183 			    ((tpAniSirGlobal) mac_handle, &qosInfo,
1184 			    adapter->session_id)) {
1185 			qosInfo.ts_info.ack_policy =
1186 				SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK;
1187 		}
1188 	}
1189 
1190 	mutex_lock(&adapter->hdd_wmm_status.wmmLock);
1191 	list_add(&pQosContext->node, &adapter->hdd_wmm_status.wmmContextList);
1192 	mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
1193 
1194 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
1195 	smeStatus = sme_qos_setup_req(mac_handle,
1196 				      adapter->session_id,
1197 				      &qosInfo,
1198 				      hdd_wmm_sme_callback,
1199 				      pQosContext,
1200 				      qosInfo.ts_info.up,
1201 				      &pQosContext->qosFlowId);
1202 
1203 	hdd_debug("sme_qos_setup_req returned %d flowid %d",
1204 		   smeStatus, pQosContext->qosFlowId);
1205 
1206 	/* need to check the return values and act appropriately */
1207 	switch (smeStatus) {
1208 	case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
1209 	case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
1210 		/* setup is pending, so no more work to do now.  all
1211 		 * further work will be done in hdd_wmm_sme_callback()
1212 		 */
1213 		hdd_debug("Setup is pending, no further work");
1214 
1215 		break;
1216 
1217 	case SME_QOS_STATUS_SETUP_FAILURE_RSP:
1218 		/* disable the inactivity timer */
1219 		hdd_wmm_disable_inactivity_timer(pQosContext);
1220 
1221 		/* we can't tell the difference between when a request
1222 		 * fails because AP rejected it versus when SME
1223 		 * encountered an internal error.  in either case SME
1224 		 * won't ever reference this context so free the
1225 		 * record
1226 		 */
1227 		hdd_wmm_free_context(pQosContext);
1228 
1229 		/* fall through and start packets flowing */
1230 	case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
1231 		/* no ACM in effect, no need to setup U-APSD */
1232 	case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
1233 		/* no ACM in effect, U-APSD is desired but was already setup */
1234 
1235 		/* for these cases everything is already setup so we
1236 		 * can signal TL that it has work to do
1237 		 */
1238 		hdd_debug("Setup is complete, notify TL");
1239 
1240 		pAc->wmmAcAccessAllowed = true;
1241 		pAc->wmmAcAccessGranted = true;
1242 		pAc->wmmAcAccessPending = false;
1243 
1244 		break;
1245 
1246 	default:
1247 		hdd_err("unexpected SME Status=%d", smeStatus);
1248 		QDF_ASSERT(0);
1249 	}
1250 #endif
1251 
1252 }
1253 
1254 /**
1255  * hdd_wmm_do_implicit_qos() - SSR wraper function for hdd_wmm_do_implicit_qos
1256  * @work: pointer to work_struct
1257  *
1258  * Return: none
1259  */
1260 static void hdd_wmm_do_implicit_qos(struct work_struct *work)
1261 {
1262 	cds_ssr_protect(__func__);
1263 	__hdd_wmm_do_implicit_qos(work);
1264 	cds_ssr_unprotect(__func__);
1265 }
1266 
1267 /**
1268  * hdd_wmm_init() - initialize the WMM DSCP configuation
1269  * @adapter : [in]  pointer to Adapter context
1270  *
1271  * This function will initialize the WMM DSCP configuation of an
1272  * adapter to an initial state.  The configuration can later be
1273  * overwritten via application APIs or via QoS Map sent OTA.
1274  *
1275  * Return: QDF_STATUS enumeration
1276  */
1277 QDF_STATUS hdd_wmm_init(struct hdd_adapter *adapter)
1278 {
1279 	enum sme_qos_wmmuptype *dscp_to_up_map = adapter->dscp_to_up_map;
1280 	uint8_t dscp;
1281 
1282 	hdd_enter();
1283 
1284 	/* DSCP to User Priority Lookup Table
1285 	 * By default use the 3 Precedence bits of DSCP as the User Priority
1286 	 */
1287 	for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++)
1288 		dscp_to_up_map[dscp] = dscp >> 3;
1289 
1290 	/* Special case for Expedited Forwarding (DSCP 46) */
1291 	dscp_to_up_map[46] = SME_QOS_WMM_UP_VO;
1292 
1293 	return QDF_STATUS_SUCCESS;
1294 }
1295 
1296 /**
1297  * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter
1298  * @adapter: [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  *
1304  * Return: QDF_STATUS enumeration
1305  */
1306 QDF_STATUS hdd_wmm_adapter_init(struct hdd_adapter *adapter)
1307 {
1308 	struct hdd_wmm_ac_status *pAcStatus;
1309 	sme_ac_enum_type acType;
1310 
1311 	hdd_enter();
1312 
1313 	adapter->hdd_wmm_status.wmmQap = false;
1314 	INIT_LIST_HEAD(&adapter->hdd_wmm_status.wmmContextList);
1315 	mutex_init(&adapter->hdd_wmm_status.wmmLock);
1316 
1317 	for (acType = 0; acType < WLAN_MAX_AC; acType++) {
1318 		pAcStatus = &adapter->hdd_wmm_status.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 	adapter->configured_psb = HDD_PSB_CFG_INVALID;
1332 
1333 	return QDF_STATUS_SUCCESS;
1334 }
1335 
1336 /**
1337  * hdd_wmm_adapter_clear() - Function which will clear the WMM status
1338  * for all the ACs
1339  *
1340  * @adapter: [in]  pointer to Adapter context
1341  *
1342  * Return: QDF_STATUS enumeration
1343  */
1344 QDF_STATUS hdd_wmm_adapter_clear(struct hdd_adapter *adapter)
1345 {
1346 	struct hdd_wmm_ac_status *pAcStatus;
1347 	sme_ac_enum_type acType;
1348 
1349 	hdd_enter();
1350 	for (acType = 0; acType < WLAN_MAX_AC; acType++) {
1351 		pAcStatus = &adapter->hdd_wmm_status.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 	}
1361 	return QDF_STATUS_SUCCESS;
1362 }
1363 
1364 /**
1365  * hdd_wmm_close() - WMM close function
1366  * @adapter: [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  *
1371  * Return: QDF_STATUS enumeration
1372  */
1373 QDF_STATUS hdd_wmm_adapter_close(struct hdd_adapter *adapter)
1374 {
1375 	struct hdd_wmm_qos_context *pQosContext;
1376 
1377 	hdd_enter();
1378 
1379 	/* free any context records that we still have linked */
1380 	while (!list_empty(&adapter->hdd_wmm_status.wmmContextList)) {
1381 		pQosContext =
1382 			list_first_entry(&adapter->hdd_wmm_status.wmmContextList,
1383 					 struct hdd_wmm_qos_context, node);
1384 
1385 		hdd_wmm_disable_inactivity_timer(pQosContext);
1386 
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 
1394 	return QDF_STATUS_SUCCESS;
1395 }
1396 
1397 /**
1398  * hdd_wmm_classify_pkt() - Function which will classify an OS packet
1399  * into a WMM AC based on DSCP
1400  *
1401  * @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
1405  *
1406  * Return: None
1407  */
1408 static
1409 void hdd_wmm_classify_pkt(struct hdd_adapter *adapter,
1410 			  struct sk_buff *skb,
1411 			  enum sme_qos_wmmuptype *user_pri,
1412 			  bool *is_eapol)
1413 {
1414 	unsigned char dscp;
1415 	unsigned char tos;
1416 	union generic_ethhdr *eth_hdr;
1417 	struct iphdr *ip_hdr;
1418 	struct ipv6hdr *ipv6hdr;
1419 	unsigned char *pkt;
1420 
1421 	/* this code is executed for every packet therefore
1422 	 * all debug code is kept conditional
1423 	 */
1424 
1425 #ifdef HDD_WMM_DEBUG
1426 	hdd_enter();
1427 #endif /* HDD_WMM_DEBUG */
1428 
1429 	pkt = skb->data;
1430 	eth_hdr = (union generic_ethhdr *)pkt;
1431 
1432 #ifdef HDD_WMM_DEBUG
1433 	hdd_debug("proto is 0x%04x", skb->protocol);
1434 #endif /* HDD_WMM_DEBUG */
1435 
1436 	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;
1440 #ifdef HDD_WMM_DEBUG
1441 		hdd_debug("Ethernet II IP Packet, tos is %d", tos);
1442 #endif /* HDD_WMM_DEBUG */
1443 
1444 	} else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) {
1445 		ipv6hdr = ipv6_hdr(skb);
1446 		tos = ntohs(*(const __be16 *)ipv6hdr) >> 4;
1447 #ifdef HDD_WMM_DEBUG
1448 		hdd_debug("Ethernet II IPv6 Packet, tos is %d", tos);
1449 #endif /* HDD_WMM_DEBUG */
1450 	} 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
1459 		hdd_debug("802.3 LLC/SNAP IP Packet, tos is %d", tos);
1460 #endif /* HDD_WMM_DEBUG */
1461 	} else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) {
1462 		/* VLAN tagged */
1463 
1464 		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;
1471 #ifdef HDD_WMM_DEBUG
1472 			hdd_debug("Ether II VLAN tagged IP Packet, tos is %d",
1473 				 tos);
1474 #endif /* HDD_WMM_DEBUG */
1475 		} 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;
1491 #ifdef HDD_WMM_DEBUG
1492 			hdd_debug("802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d",
1493 				 tos);
1494 #endif /* HDD_WMM_DEBUG */
1495 		} else {
1496 			/* default */
1497 #ifdef HDD_WMM_DEBUG
1498 			hdd_warn("VLAN tagged Unhandled Protocol, using default tos");
1499 #endif /* HDD_WMM_DEBUG */
1500 			tos = 0;
1501 		}
1502 	} else {
1503 		/* default */
1504 #ifdef HDD_WMM_DEBUG
1505 		hdd_warn("Unhandled Protocol, using default tos");
1506 #endif /* HDD_WMM_DEBUG */
1507 		/* 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;
1514 	}
1515 
1516 	dscp = (tos >> 2) & 0x3f;
1517 	*user_pri = adapter->dscp_to_up_map[dscp];
1518 
1519 #ifdef HDD_WMM_DEBUG
1520 	hdd_debug("tos is %d, dscp is %d, up is %d", tos, dscp, *user_pri);
1521 #endif /* HDD_WMM_DEBUG */
1522 }
1523 
1524 /**
1525  * __hdd_get_queue_index() - get queue index
1526  * @up: user priority
1527  *
1528  * Return: queue_index
1529  */
1530 static uint16_t __hdd_get_queue_index(uint16_t up)
1531 {
1532 	if (qdf_unlikely(up >= ARRAY_SIZE(hdd_linux_up_to_ac_map)))
1533 		return HDD_LINUX_AC_BE;
1534 	return hdd_linux_up_to_ac_map[up];
1535 }
1536 
1537 #if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_HL_NETDEV_FLOW_CONTROL)
1538 /**
1539  * hdd_get_queue_index() - get queue index
1540  * @up: user priority
1541  * @is_eapol: is_eapol flag
1542  *
1543  * Return: queue_index
1544  */
1545 static
1546 uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol)
1547 {
1548 	if (qdf_unlikely(is_eapol == true))
1549 		return HDD_LINUX_AC_HI_PRIO;
1550 	return __hdd_get_queue_index(up);
1551 }
1552 #else
1553 static
1554 uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol)
1555 {
1556 	return __hdd_get_queue_index(up);
1557 }
1558 #endif
1559 
1560 
1561 /**
1562  * hdd_hostapd_select_queue() - Function which will classify the packet
1563  *       according to linux qdisc expectation.
1564  *
1565  * @dev: [in] pointer to net_device structure
1566  * @skb: [in] pointer to os packet
1567  *
1568  * Return: Qdisc queue index
1569  */
1570 uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb
1571 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
1572 				  , void *accel_priv
1573 #endif
1574 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
1575 				  , select_queue_fallback_t fallback
1576 #endif
1577 
1578 )
1579 {
1580 	enum sme_qos_wmmuptype up = SME_QOS_WMM_UP_BE;
1581 	uint16_t queueIndex;
1582 	struct hdd_adapter *adapter = (struct hdd_adapter *) netdev_priv(dev);
1583 	struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter);
1584 	bool is_eapol = false;
1585 	int status = 0;
1586 
1587 	status = wlan_hdd_validate_context(hddctx);
1588 
1589 	if (status != 0) {
1590 		skb->priority = SME_QOS_WMM_UP_BE;
1591 		return HDD_LINUX_AC_BE;
1592 	}
1593 
1594 	/* Get the user priority from IP header */
1595 	hdd_wmm_classify_pkt(adapter, skb, &up, &is_eapol);
1596 	skb->priority = up;
1597 	queueIndex = hdd_get_queue_index(skb->priority, is_eapol);
1598 
1599 	return queueIndex;
1600 }
1601 
1602 /**
1603  * hdd_wmm_select_queue() - Function which will classify the packet
1604  *       according to linux qdisc expectation.
1605  *
1606  * @dev: [in] pointer to net_device structure
1607  * @skb: [in] pointer to os packet
1608  *
1609  * Return: Qdisc queue index
1610  */
1611 uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb)
1612 {
1613 	enum sme_qos_wmmuptype up = SME_QOS_WMM_UP_BE;
1614 	uint16_t queueIndex;
1615 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1616 	bool is_crtical = false;
1617 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1618 	int status;
1619 	enum qdf_proto_subtype proto_subtype;
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 	}
1626 
1627 	/* Get the user priority from IP header */
1628 	hdd_wmm_classify_pkt(adapter, skb, &up, &is_crtical);
1629 	spin_lock_bh(&adapter->pause_map_lock);
1630 	if ((adapter->pause_map & (1 <<  WLAN_DATA_FLOW_CONTROL)) &&
1631 	   !(adapter->pause_map & (1 <<  WLAN_DATA_FLOW_CONTROL_PRIORITY))) {
1632 		if (qdf_nbuf_is_ipv4_arp_pkt(skb))
1633 			is_crtical = true;
1634 		else if (qdf_nbuf_is_icmpv6_pkt(skb)) {
1635 			proto_subtype = qdf_nbuf_get_icmpv6_subtype(skb);
1636 			switch (proto_subtype) {
1637 			case QDF_PROTO_ICMPV6_NA:
1638 			case QDF_PROTO_ICMPV6_NS:
1639 				is_crtical = true;
1640 				break;
1641 			default:
1642 				break;
1643 			}
1644 		}
1645 	}
1646 	spin_unlock_bh(&adapter->pause_map_lock);
1647 	skb->priority = up;
1648 	queueIndex = hdd_get_queue_index(skb->priority, is_crtical);
1649 
1650 	return queueIndex;
1651 }
1652 
1653 /**
1654  * hdd_wmm_acquire_access_required() - Function which will determine
1655  * acquire admittance for a WMM AC is required or not based on psb configuration
1656  * done in framework
1657  *
1658  * @adapter: [in] pointer to adapter structure
1659  * @acType: [in] WMM AC type of OS packet
1660  *
1661  * Return: void
1662  */
1663 void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter,
1664 				     sme_ac_enum_type acType)
1665 {
1666 	/* Each bit in the LSB nibble indicates 1 AC.
1667 	 * Clearing the particular bit in LSB nibble to indicate
1668 	 * access required
1669 	 */
1670 	switch (acType) {
1671 	case SME_AC_BK:
1672 		/* clear first bit */
1673 		adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK;
1674 		break;
1675 	case SME_AC_BE:
1676 		/* clear second bit */
1677 		adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK;
1678 		break;
1679 	case SME_AC_VI:
1680 		/* clear third bit */
1681 		adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK;
1682 		break;
1683 	case SME_AC_VO:
1684 		/* clear fourth bit */
1685 		adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK;
1686 		break;
1687 	default:
1688 		hdd_err("Invalid AC Type");
1689 		break;
1690 	}
1691 }
1692 
1693 /**
1694  * hdd_wmm_acquire_access() - Function which will attempt to acquire
1695  * admittance for a WMM AC
1696  *
1697  * @adapter: [in]  pointer to adapter context
1698  * @acType: [in]  WMM AC type of OS packet
1699  * @pGranted: [out] pointer to bool flag when indicates if access
1700  *	      has been granted or not
1701  *
1702  * Return: QDF_STATUS enumeration
1703  */
1704 QDF_STATUS hdd_wmm_acquire_access(struct hdd_adapter *adapter,
1705 				  sme_ac_enum_type acType, bool *pGranted)
1706 {
1707 	struct hdd_wmm_qos_context *pQosContext;
1708 
1709 	QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
1710 		  "%s: Entered for AC %d", __func__, acType);
1711 
1712 	if (!hdd_wmm_is_active(adapter) ||
1713 	    !(WLAN_HDD_GET_CTX(adapter))->config->bImplicitQosEnabled ||
1714 	    !adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessRequired) {
1715 		/* either we don't want QoS or the AP doesn't support
1716 		 * QoS or we don't want to do implicit QoS
1717 		 */
1718 		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
1719 			  "%s: QoS not configured on both ends ", __func__);
1720 
1721 		*pGranted =
1722 			adapter->hdd_wmm_status.wmmAcStatus[acType].
1723 			wmmAcAccessAllowed;
1724 
1725 		return QDF_STATUS_SUCCESS;
1726 	}
1727 	/* do we already have an implicit QoS request pending for this AC? */
1728 	if ((adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessNeeded) ||
1729 	    (adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessPending)) {
1730 		/* request already pending so we need to wait for that
1731 		 * response
1732 		 */
1733 		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
1734 			  "%s: Implicit QoS for TL AC %d already scheduled",
1735 			  __func__, acType);
1736 
1737 		*pGranted = false;
1738 		return QDF_STATUS_SUCCESS;
1739 	}
1740 	/* did we already fail to establish implicit QoS for this AC?
1741 	 * (if so, access should have been granted when the failure
1742 	 * was handled)
1743 	 */
1744 	if (adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessFailed) {
1745 		/* request previously failed
1746 		 * allow access, but we'll be downgraded
1747 		 */
1748 		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
1749 			  "%s: Implicit QoS for TL AC %d previously failed",
1750 			  __func__, acType);
1751 
1752 		if (!adapter->hdd_wmm_status.wmmAcStatus[acType].
1753 		    wmmAcAccessRequired) {
1754 			adapter->hdd_wmm_status.wmmAcStatus[acType].
1755 			wmmAcAccessAllowed = true;
1756 			*pGranted = true;
1757 		} else {
1758 			adapter->hdd_wmm_status.wmmAcStatus[acType].
1759 			wmmAcAccessAllowed = false;
1760 			*pGranted = false;
1761 		}
1762 
1763 		return QDF_STATUS_SUCCESS;
1764 	}
1765 	/* we need to establish implicit QoS */
1766 	QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
1767 		  "%s: Need to schedule implicit QoS for TL AC %d, adapter is %pK",
1768 		  __func__, acType, adapter);
1769 
1770 	adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessNeeded = true;
1771 
1772 	pQosContext = qdf_mem_malloc(sizeof(*pQosContext));
1773 	if (NULL == pQosContext) {
1774 		/* no memory for QoS context.  Nothing we can do but
1775 		 * let data flow
1776 		 */
1777 		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR,
1778 			  "%s: Unable to allocate context", __func__);
1779 		adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessAllowed =
1780 			true;
1781 		*pGranted = true;
1782 		return QDF_STATUS_SUCCESS;
1783 	}
1784 
1785 	pQosContext->acType = acType;
1786 	pQosContext->adapter = adapter;
1787 	pQosContext->qosFlowId = 0;
1788 	pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT;
1789 	pQosContext->magic = HDD_WMM_CTX_MAGIC;
1790 	pQosContext->is_inactivity_timer_running = false;
1791 
1792 	INIT_WORK(&pQosContext->wmmAcSetupImplicitQos, hdd_wmm_do_implicit_qos);
1793 
1794 	QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG,
1795 		  "%s: Scheduling work for AC %d, context %pK",
1796 		  __func__, acType, pQosContext);
1797 
1798 	schedule_work(&pQosContext->wmmAcSetupImplicitQos);
1799 
1800 	/* caller will need to wait until the work takes place and
1801 	 * TSPEC negotiation completes
1802 	 */
1803 	*pGranted = false;
1804 	return QDF_STATUS_SUCCESS;
1805 }
1806 
1807 /**
1808  * hdd_wmm_assoc() - Function which will handle the housekeeping
1809  * required by WMM when association takes place
1810  *
1811  * @adapter: [in]  pointer to adapter context
1812  * @roam_info: [in]  pointer to roam information
1813  * @eBssType: [in]  type of BSS
1814  *
1815  * Return: QDF_STATUS enumeration
1816  */
1817 QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter,
1818 			 struct csr_roam_info *roam_info,
1819 			 eCsrRoamBssType eBssType)
1820 {
1821 	uint8_t uapsdMask;
1822 	QDF_STATUS status;
1823 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1824 
1825 	/* when we associate we need to notify TL if it needs to
1826 	 * enable UAPSD for any access categories
1827 	 */
1828 
1829 	hdd_enter();
1830 
1831 	if (roam_info->fReassocReq) {
1832 		/* when we reassociate we should continue to use
1833 		 * whatever parameters were previously established.
1834 		 * if we are reassociating due to a U-APSD change for
1835 		 * a particular Access Category, then the change will
1836 		 * be communicated to HDD via the QoS callback
1837 		 * associated with the given flow, and U-APSD
1838 		 * parameters will be updated there
1839 		 */
1840 
1841 		hdd_debug("Reassoc so no work, Exiting");
1842 
1843 		return QDF_STATUS_SUCCESS;
1844 	}
1845 	/* get the negotiated UAPSD Mask */
1846 	uapsdMask =
1847 		roam_info->u.pConnectedProfile->modifyProfileFields.uapsd_mask;
1848 
1849 	hdd_debug("U-APSD mask is 0x%02x", (int)uapsdMask);
1850 
1851 	if (uapsdMask & HDD_AC_VO) {
1852 		status =
1853 			sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR
1854 							    (adapter))->conn_info.staId[0],
1855 						   SME_AC_VO, 7, 7,
1856 						   hdd_ctx->config->InfraUapsdVoSrvIntv,
1857 						   hdd_ctx->config->InfraUapsdVoSuspIntv,
1858 						   SME_QOS_WMM_TS_DIR_BOTH, 1,
1859 						   adapter->session_id,
1860 						   hdd_ctx->config->DelayedTriggerFrmInt);
1861 
1862 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
1863 	}
1864 
1865 	if (uapsdMask & HDD_AC_VI) {
1866 		status =
1867 			sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR
1868 							    (adapter))->conn_info.staId[0],
1869 						   SME_AC_VI, 5, 5,
1870 						   hdd_ctx->config->InfraUapsdViSrvIntv,
1871 						   hdd_ctx->config->InfraUapsdViSuspIntv,
1872 						   SME_QOS_WMM_TS_DIR_BOTH, 1,
1873 						   adapter->session_id,
1874 						   hdd_ctx->config->DelayedTriggerFrmInt);
1875 
1876 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
1877 	}
1878 
1879 	if (uapsdMask & HDD_AC_BK) {
1880 		status =
1881 			sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR
1882 							    (adapter))->conn_info.staId[0],
1883 						   SME_AC_BK, 2, 2,
1884 						   hdd_ctx->config->InfraUapsdBkSrvIntv,
1885 						   hdd_ctx->config->InfraUapsdBkSuspIntv,
1886 						   SME_QOS_WMM_TS_DIR_BOTH, 1,
1887 						   adapter->session_id,
1888 						   hdd_ctx->config->DelayedTriggerFrmInt);
1889 
1890 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
1891 	}
1892 
1893 	if (uapsdMask & HDD_AC_BE) {
1894 		status =
1895 			sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR
1896 							    (adapter))->conn_info.staId[0],
1897 						   SME_AC_BE, 3, 3,
1898 						   hdd_ctx->config->InfraUapsdBeSrvIntv,
1899 						   hdd_ctx->config->InfraUapsdBeSuspIntv,
1900 						   SME_QOS_WMM_TS_DIR_BOTH, 1,
1901 						   adapter->session_id,
1902 						   hdd_ctx->config->DelayedTriggerFrmInt);
1903 
1904 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status));
1905 	}
1906 
1907 	status = sme_update_dsc_pto_up_mapping(hdd_ctx->mac_handle,
1908 					       adapter->dscp_to_up_map,
1909 					       adapter->session_id);
1910 
1911 	if (!QDF_IS_STATUS_SUCCESS(status))
1912 		hdd_wmm_init(adapter);
1913 
1914 	hdd_exit();
1915 
1916 	return QDF_STATUS_SUCCESS;
1917 }
1918 
1919 static const uint8_t acm_mask_bit[WLAN_MAX_AC] = {
1920 	0x4,                    /* SME_AC_BK */
1921 	0x8,                    /* SME_AC_BE */
1922 	0x2,                    /* SME_AC_VI */
1923 	0x1                     /* SME_AC_VO */
1924 };
1925 
1926 /**
1927  * hdd_wmm_connect() - Function which will handle the housekeeping
1928  * required by WMM when a connection is established
1929  *
1930  * @adapter : [in]  pointer to adapter context
1931  * @roam_info: [in]  pointer to roam information
1932  * @eBssType : [in]  type of BSS
1933  *
1934  * Return: QDF_STATUS enumeration
1935  */
1936 QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter,
1937 			   struct csr_roam_info *roam_info,
1938 			   eCsrRoamBssType eBssType)
1939 {
1940 	int ac;
1941 	bool qap;
1942 	bool qosConnection;
1943 	uint8_t acmMask;
1944 	mac_handle_t mac_handle;
1945 
1946 	hdd_enter();
1947 
1948 	if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) &&
1949 	    roam_info && roam_info->u.pConnectedProfile) {
1950 		qap = roam_info->u.pConnectedProfile->qap;
1951 		qosConnection = roam_info->u.pConnectedProfile->qosConnection;
1952 		acmMask = roam_info->u.pConnectedProfile->acm_mask;
1953 	} else {
1954 		qap = true;
1955 		qosConnection = true;
1956 		acmMask = 0x0;
1957 	}
1958 
1959 	hdd_debug("qap is %d, qosConnection is %d, acmMask is 0x%x",
1960 		 qap, qosConnection, acmMask);
1961 
1962 	adapter->hdd_wmm_status.wmmQap = qap;
1963 	adapter->hdd_wmm_status.wmmQosConnection = qosConnection;
1964 	mac_handle = hdd_adapter_get_mac_handle(adapter);
1965 
1966 	for (ac = 0; ac < WLAN_MAX_AC; ac++) {
1967 		if (qap && qosConnection && (acmMask & acm_mask_bit[ac])) {
1968 			hdd_debug("ac %d on", ac);
1969 
1970 			/* admission is required */
1971 			adapter->hdd_wmm_status.wmmAcStatus[ac].
1972 			wmmAcAccessRequired = true;
1973 			adapter->hdd_wmm_status.wmmAcStatus[ac].
1974 			wmmAcAccessAllowed = false;
1975 			adapter->hdd_wmm_status.wmmAcStatus[ac].
1976 			wmmAcAccessGranted = false;
1977 			/* after reassoc if we have valid tspec, allow access */
1978 			if (adapter->hdd_wmm_status.wmmAcStatus[ac].
1979 			    wmmAcTspecValid
1980 			    && (adapter->hdd_wmm_status.wmmAcStatus[ac].
1981 				wmmAcTspecInfo.ts_info.direction !=
1982 				SME_QOS_WMM_TS_DIR_DOWNLINK)) {
1983 				adapter->hdd_wmm_status.wmmAcStatus[ac].
1984 				wmmAcAccessAllowed = true;
1985 			}
1986 			if (!roam_info->fReassocReq &&
1987 			    !sme_neighbor_roam_is11r_assoc(
1988 						mac_handle,
1989 						adapter->session_id) &&
1990 			    !sme_roam_is_ese_assoc(roam_info)) {
1991 				adapter->hdd_wmm_status.wmmAcStatus[ac].
1992 					wmmAcTspecValid = false;
1993 				adapter->hdd_wmm_status.wmmAcStatus[ac].
1994 					wmmAcAccessAllowed = false;
1995 			}
1996 		} else {
1997 			hdd_debug("ac %d off", ac);
1998 			/* admission is not required so access is allowed */
1999 			adapter->hdd_wmm_status.wmmAcStatus[ac].
2000 			wmmAcAccessRequired = false;
2001 			adapter->hdd_wmm_status.wmmAcStatus[ac].
2002 			wmmAcAccessAllowed = true;
2003 		}
2004 
2005 	}
2006 
2007 	hdd_exit();
2008 
2009 	return QDF_STATUS_SUCCESS;
2010 }
2011 
2012 /**
2013  * hdd_wmm_get_uapsd_mask() - Function which will calculate the
2014  * initial value of the UAPSD mask based upon the device configuration
2015  *
2016  * @adapter  : [in]  pointer to adapter context
2017  * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored
2018  *
2019  * Return: QDF_STATUS enumeration
2020  */
2021 QDF_STATUS hdd_wmm_get_uapsd_mask(struct hdd_adapter *adapter,
2022 				  uint8_t *pUapsdMask)
2023 {
2024 	uint8_t uapsdMask;
2025 
2026 	if (HDD_WMM_USER_MODE_NO_QOS ==
2027 	    (WLAN_HDD_GET_CTX(adapter))->config->WmmMode) {
2028 		/* no QOS then no UAPSD */
2029 		uapsdMask = 0;
2030 	} else {
2031 		/* start with the default mask */
2032 		uapsdMask = (WLAN_HDD_GET_CTX(adapter))->config->UapsdMask;
2033 
2034 		/* disable UAPSD for any ACs with a 0 Service Interval */
2035 		if ((WLAN_HDD_GET_CTX(adapter))->config->
2036 		    InfraUapsdVoSrvIntv == 0) {
2037 			uapsdMask &= ~HDD_AC_VO;
2038 		}
2039 
2040 		if ((WLAN_HDD_GET_CTX(adapter))->config->
2041 		    InfraUapsdViSrvIntv == 0) {
2042 			uapsdMask &= ~HDD_AC_VI;
2043 		}
2044 
2045 		if ((WLAN_HDD_GET_CTX(adapter))->config->
2046 		    InfraUapsdBkSrvIntv == 0) {
2047 			uapsdMask &= ~HDD_AC_BK;
2048 		}
2049 
2050 		if ((WLAN_HDD_GET_CTX(adapter))->config->
2051 		    InfraUapsdBeSrvIntv == 0) {
2052 			uapsdMask &= ~HDD_AC_BE;
2053 		}
2054 	}
2055 
2056 	/* return calculated mask */
2057 	*pUapsdMask = uapsdMask;
2058 	return QDF_STATUS_SUCCESS;
2059 }
2060 
2061 /**
2062  * hdd_wmm_is_active() - Function which will determine if WMM is
2063  * active on the current connection
2064  *
2065  * @adapter: [in]  pointer to adapter context
2066  *
2067  * Return: true if WMM is enabled, false if WMM is not enabled
2068  */
2069 bool hdd_wmm_is_active(struct hdd_adapter *adapter)
2070 {
2071 	if ((!adapter->hdd_wmm_status.wmmQosConnection) ||
2072 	    (!adapter->hdd_wmm_status.wmmQap)) {
2073 		return false;
2074 	} else {
2075 		return true;
2076 	}
2077 }
2078 
2079 bool hdd_wmm_is_acm_allowed(struct wlan_objmgr_vdev **vdev)
2080 {
2081 	struct hdd_adapter *adapter;
2082 	struct hdd_wmm_ac_status *wmm_ac_status;
2083 
2084 
2085 	adapter = container_of(vdev, struct hdd_adapter, hdd_vdev);
2086 	if (NULL == adapter) {
2087 		hdd_err("failed, hdd adapter is NULL");
2088 		return false;
2089 	}
2090 	wmm_ac_status = adapter->hdd_wmm_status.wmmAcStatus;
2091 
2092 	if (hdd_wmm_is_active(adapter) &&
2093 	    !(wmm_ac_status[OL_TX_WMM_AC_VI].wmmAcAccessAllowed))
2094 		return false;
2095 	return true;
2096 }
2097 
2098 /**
2099  * hdd_wmm_addts() - Function which will add a traffic spec at the
2100  * request of an application
2101  *
2102  * @adapter  : [in]  pointer to adapter context
2103  * @handle    : [in]  handle to uniquely identify a TS
2104  * @pTspec    : [in]  pointer to the traffic spec
2105  *
2106  * Return: HDD_WLAN_WMM_STATUS_*
2107  */
2108 hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter,
2109 				    uint32_t handle,
2110 				    struct sme_qos_wmmtspecinfo *pTspec)
2111 {
2112 	struct hdd_wmm_qos_context *pQosContext;
2113 	hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2114 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
2115 	enum sme_qos_statustype smeStatus;
2116 #endif
2117 	bool found = false;
2118 	mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
2119 
2120 	hdd_debug("Entered with handle 0x%x", handle);
2121 
2122 	/* see if a context already exists with the given handle */
2123 	mutex_lock(&adapter->hdd_wmm_status.wmmLock);
2124 	list_for_each_entry(pQosContext,
2125 			    &adapter->hdd_wmm_status.wmmContextList, node) {
2126 		if (pQosContext->handle == handle) {
2127 			found = true;
2128 			break;
2129 		}
2130 	}
2131 	mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
2132 	if (found) {
2133 		/* record with that handle already exists */
2134 		hdd_err("Record already exists with handle 0x%x", handle);
2135 
2136 		/* Application is trying to modify some of the Tspec
2137 		 * params. Allow it
2138 		 */
2139 		smeStatus = sme_qos_modify_req(mac_handle,
2140 					       pTspec, pQosContext->qosFlowId);
2141 
2142 		/* need to check the return value and act appropriately */
2143 		switch (smeStatus) {
2144 		case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP:
2145 			status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING;
2146 			break;
2147 		case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2148 			status =
2149 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD;
2150 			break;
2151 		case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY:
2152 			status =
2153 				HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING;
2154 			break;
2155 		case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP:
2156 			status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM;
2157 			break;
2158 		case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP:
2159 			status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2160 			break;
2161 		case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2162 			status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2163 			break;
2164 		default:
2165 			/* we didn't get back one of the
2166 			 * SME_QOS_STATUS_MODIFY_* status codes
2167 			 */
2168 			hdd_err("unexpected SME Status=%d",
2169 				  smeStatus);
2170 			QDF_ASSERT(0);
2171 			return HDD_WLAN_WMM_STATUS_MODIFY_FAILED;
2172 		}
2173 
2174 		/* we were successful, save the status */
2175 		mutex_lock(&adapter->hdd_wmm_status.wmmLock);
2176 		if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2177 			pQosContext->lastStatus = status;
2178 		mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
2179 
2180 		return status;
2181 	}
2182 
2183 	pQosContext = qdf_mem_malloc(sizeof(*pQosContext));
2184 	if (NULL == pQosContext) {
2185 		/* no memory for QoS context.  Nothing we can do */
2186 		hdd_err("Unable to allocate QoS context");
2187 		return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE;
2188 	}
2189 	/* we assume the tspec has already been validated by the caller */
2190 
2191 	pQosContext->handle = handle;
2192 	if (pTspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE)
2193 		pQosContext->acType = hdd_wmm_up_to_ac_map[pTspec->ts_info.up];
2194 	else {
2195 		hdd_err("ts_info.up (%d) larger than max value (%d), use default acType (%d)",
2196 			pTspec->ts_info.up,
2197 			HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]);
2198 		pQosContext->acType = hdd_wmm_up_to_ac_map[0];
2199 	}
2200 	pQosContext->adapter = adapter;
2201 	pQosContext->qosFlowId = 0;
2202 	pQosContext->magic = HDD_WMM_CTX_MAGIC;
2203 	pQosContext->is_inactivity_timer_running = false;
2204 
2205 	hdd_debug("Setting up QoS, context %pK", pQosContext);
2206 
2207 	mutex_lock(&adapter->hdd_wmm_status.wmmLock);
2208 	list_add(&pQosContext->node, &adapter->hdd_wmm_status.wmmContextList);
2209 	mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
2210 
2211 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
2212 	smeStatus = sme_qos_setup_req(mac_handle,
2213 				      adapter->session_id,
2214 				      pTspec,
2215 				      hdd_wmm_sme_callback,
2216 				      pQosContext,
2217 				      pTspec->ts_info.up,
2218 				      &pQosContext->qosFlowId);
2219 
2220 	hdd_debug("sme_qos_setup_req returned %d flowid %d",
2221 		   smeStatus, pQosContext->qosFlowId);
2222 
2223 	/* need to check the return value and act appropriately */
2224 	switch (smeStatus) {
2225 	case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP:
2226 		status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2227 		break;
2228 	case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP:
2229 		status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD;
2230 		break;
2231 	case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY:
2232 		status =
2233 			HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING;
2234 		break;
2235 	case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING:
2236 		status = HDD_WLAN_WMM_STATUS_SETUP_PENDING;
2237 		break;
2238 	case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP:
2239 		/* disable the inactivity timer */
2240 		hdd_wmm_disable_inactivity_timer(pQosContext);
2241 		hdd_wmm_free_context(pQosContext);
2242 		return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM;
2243 	case SME_QOS_STATUS_SETUP_FAILURE_RSP:
2244 		/* disable the inactivity timer */
2245 		hdd_wmm_disable_inactivity_timer(pQosContext);
2246 		/* we can't tell the difference between when a request
2247 		 * fails because AP rejected it versus when SME
2248 		 * encounterd an internal error
2249 		 */
2250 		hdd_wmm_free_context(pQosContext);
2251 		return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2252 	case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP:
2253 		/* disable the inactivity timer */
2254 		hdd_wmm_disable_inactivity_timer(pQosContext);
2255 		hdd_wmm_free_context(pQosContext);
2256 		return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM;
2257 	default:
2258 		/* disable the inactivity timer */
2259 		hdd_wmm_disable_inactivity_timer(pQosContext);
2260 		/* we didn't get back one of the
2261 		 * SME_QOS_STATUS_SETUP_* status codes
2262 		 */
2263 		hdd_wmm_free_context(pQosContext);
2264 		hdd_err("unexpected SME Status=%d", smeStatus);
2265 		QDF_ASSERT(0);
2266 		return HDD_WLAN_WMM_STATUS_SETUP_FAILED;
2267 	}
2268 #endif
2269 
2270 	/* we were successful, save the status */
2271 	mutex_lock(&adapter->hdd_wmm_status.wmmLock);
2272 	if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2273 		pQosContext->lastStatus = status;
2274 	mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
2275 
2276 	return status;
2277 }
2278 
2279 /**
2280  * hdd_wmm_delts() - Function which will delete a traffic spec at the
2281  * request of an application
2282  *
2283  * @adapter: [in]  pointer to adapter context
2284  * @handle: [in]  handle to uniquely identify a TS
2285  *
2286  * Return: HDD_WLAN_WMM_STATUS_*
2287  */
2288 hdd_wlan_wmm_status_e hdd_wmm_delts(struct hdd_adapter *adapter,
2289 				    uint32_t handle)
2290 {
2291 	struct hdd_wmm_qos_context *pQosContext;
2292 	bool found = false;
2293 	sme_ac_enum_type acType = 0;
2294 	uint32_t qosFlowId = 0;
2295 	hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS;
2296 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
2297 	enum sme_qos_statustype smeStatus;
2298 	mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
2299 #endif
2300 
2301 	hdd_debug("Entered with handle 0x%x", handle);
2302 
2303 	/* locate the context with the given handle */
2304 	mutex_lock(&adapter->hdd_wmm_status.wmmLock);
2305 	list_for_each_entry(pQosContext,
2306 			    &adapter->hdd_wmm_status.wmmContextList, node) {
2307 		if (pQosContext->handle == handle) {
2308 			found = true;
2309 			acType = pQosContext->acType;
2310 			qosFlowId = pQosContext->qosFlowId;
2311 			break;
2312 		}
2313 	}
2314 	mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
2315 
2316 	if (false == found) {
2317 		/* we didn't find the handle */
2318 		hdd_info("handle 0x%x not found", handle);
2319 		return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2320 	}
2321 
2322 	hdd_debug("found handle 0x%x, flow %d, AC %d, context %pK",
2323 		 handle, qosFlowId, acType, pQosContext);
2324 
2325 #ifndef WLAN_MDM_CODE_REDUCTION_OPT
2326 	smeStatus = sme_qos_release_req(mac_handle, adapter->session_id,
2327 					qosFlowId);
2328 
2329 	hdd_debug("SME flow %d released, SME status %d", qosFlowId, smeStatus);
2330 
2331 	switch (smeStatus) {
2332 	case SME_QOS_STATUS_RELEASE_SUCCESS_RSP:
2333 		/* this flow is the only one on that AC, so go ahead
2334 		 * and update our TSPEC state for the AC
2335 		 */
2336 		adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcTspecValid =
2337 			false;
2338 		adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessAllowed =
2339 			false;
2340 
2341 		/* need to tell TL to stop trigger timer, etc */
2342 		hdd_wmm_disable_tl_uapsd(pQosContext);
2343 
2344 		/* disable the inactivity timer */
2345 		hdd_wmm_disable_inactivity_timer(pQosContext);
2346 
2347 		/* we are done with this context */
2348 		hdd_wmm_free_context(pQosContext);
2349 
2350 		/* SME must not fire any more callbacks for this flow
2351 		 * since the context is no longer valid
2352 		 */
2353 
2354 		return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS;
2355 
2356 	case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP:
2357 		/* do nothing as we will get a response from SME */
2358 		status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING;
2359 		break;
2360 
2361 	case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP:
2362 		/* nothing we can do with the existing flow except leave it */
2363 		status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM;
2364 		break;
2365 
2366 	case SME_QOS_STATUS_RELEASE_FAILURE_RSP:
2367 		/* nothing we can do with the existing flow except leave it */
2368 		status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2369 		break;
2370 
2371 	default:
2372 		/* we didn't get back one of the
2373 		 * SME_QOS_STATUS_RELEASE_* status codes
2374 		 */
2375 		hdd_err("unexpected SME Status=%d", smeStatus);
2376 		QDF_ASSERT(0);
2377 		status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED;
2378 	}
2379 
2380 #endif
2381 	mutex_lock(&adapter->hdd_wmm_status.wmmLock);
2382 	if (pQosContext->magic == HDD_WMM_CTX_MAGIC)
2383 		pQosContext->lastStatus = status;
2384 	mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
2385 
2386 	return status;
2387 }
2388 
2389 /**
2390  * hdd_wmm_checkts() - Function which will return the status of a traffic
2391  * spec at the request of an application
2392  *
2393  * @adapter: [in]  pointer to adapter context
2394  * @handle: [in]  handle to uniquely identify a TS
2395  *
2396  * Return: HDD_WLAN_WMM_STATUS_*
2397  */
2398 hdd_wlan_wmm_status_e hdd_wmm_checkts(struct hdd_adapter *adapter, uint32_t handle)
2399 {
2400 	struct hdd_wmm_qos_context *pQosContext;
2401 	hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST;
2402 
2403 	hdd_debug("Entered with handle 0x%x", handle);
2404 
2405 	/* locate the context with the given handle */
2406 	mutex_lock(&adapter->hdd_wmm_status.wmmLock);
2407 	list_for_each_entry(pQosContext,
2408 			    &adapter->hdd_wmm_status.wmmContextList, node) {
2409 		if (pQosContext->handle == handle) {
2410 			hdd_debug("found handle 0x%x, context %pK",
2411 				 handle, pQosContext);
2412 
2413 			status = pQosContext->lastStatus;
2414 			break;
2415 		}
2416 	}
2417 	mutex_unlock(&adapter->hdd_wmm_status.wmmLock);
2418 	return status;
2419 }
2420