1 /*
2  * Copyright (c) 2011-2012,2016-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #ifndef _WLAN_HDD_WMM_H
21 #define _WLAN_HDD_WMM_H
22 
23 /**
24  * DOC: HDD WMM
25  *
26  * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation)
27  * houses all the logic for WMM in HDD.
28  *
29  * On the control path, it has the logic to setup QoS, modify QoS and delete
30  * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an
31  * explicit application invoked and an internal HDD invoked.  The implicit QoS
32  * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but
33  * which DO mark their traffic for priortization. It also has logic to start,
34  * update and stop the U-APSD trigger frame generation. It also has logic to
35  * read WMM related config parameters from the registry.
36  *
37  * On the data path, it has the logic to figure out the WMM AC of an egress
38  * packet and when to signal TL to serve a particular AC queue. It also has the
39  * logic to retrieve a packet based on WMM priority in response to a fetch from
40  * TL.
41  *
42  * The remaining functions are utility functions for information hiding.
43  */
44 
45 /* Include files */
46 #include <linux/workqueue.h>
47 #include <linux/list.h>
48 #include <wlan_hdd_main.h>
49 #include <wlan_hdd_wext.h>
50 #include <sme_qos_api.h>
51 #include <qca_vendor.h>
52 
53 /*Maximum number of ACs */
54 #define WLAN_MAX_AC                         4
55 
56 
57 /* Preprocessor Definitions and Constants */
58 
59 /* #define HDD_WMM_DEBUG 1 */
60 
61 #define HDD_WMM_CTX_MAGIC 0x574d4d58    /* "WMMX" */
62 
63 #define HDD_WMM_HANDLE_IMPLICIT 0xFFFFFFFF
64 
65 #define HDD_WLAN_INVALID_STA_ID 0xFF
66 
67 /* Type Declarations */
68 
69 /**
70  * enum hdd_wmm_user_mode - WMM modes of operation
71  *
72  * @HDD_WMM_USER_MODE_AUTO: STA can associate with any AP, & HDD looks at
73  *	the SME notification after association to find out if associated
74  *	with QAP and acts accordingly
75  * @HDD_WMM_USER_MODE_QBSS_ONLY: SME will add the extra logic to make sure
76  *	STA associates with a QAP only
77  * @HDD_WMM_USER_MODE_NO_QOS: Join any AP, but uapsd is disabled
78  */
79 enum hdd_wmm_user_mode {
80 	HDD_WMM_USER_MODE_AUTO = 0,
81 	HDD_WMM_USER_MODE_QBSS_ONLY = 1,
82 	HDD_WMM_USER_MODE_NO_QOS = 2,
83 };
84 
85 /* UAPSD Mask bits */
86 /* (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) */
87 #define HDD_AC_VO 0x1
88 #define HDD_AC_VI 0x2
89 #define HDD_AC_BK 0x4
90 #define HDD_AC_BE 0x8
91 
92 /**
93  * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to
94  * operate on different traffic.
95  * @HDD_LINUX_AC_VO: voice priority
96  * @HDD_LINUX_AC_VI: video priority
97  * @HDD_LINUX_AC_BE: best effort priority
98  * @HDD_LINUX_AC_BK: background priority
99  * @HDD_LINUX_AC_HI_PRIO: unclassified high priority
100  */
101 enum hdd_wmm_linuxac {
102 	HDD_LINUX_AC_VO = 0,
103 	HDD_LINUX_AC_VI = 1,
104 	HDD_LINUX_AC_BE = 2,
105 	HDD_LINUX_AC_BK = 3,
106 	HDD_LINUX_AC_HI_PRIO = 4,
107 };
108 
109 /**
110  * struct hdd_wmm_qos_context - HDD WMM QoS Context
111  *
112  * This structure holds the context for a single flow which has either
113  * been configured explicitly from userspace or implicitly via the
114  * Implicit QoS feature.
115  *
116  * @node: list node which can be used to put the context into a list
117  *	of contexts
118  * @handle: identifier which uniquely identifies this context to userspace
119  * @flow_id: identifier which uniquely identifies this flow to SME
120  * @adapter: adapter upon which this flow was configured
121  * @ac_type: access category for this flow
122  * @status: the status of the last operation performed on this flow by SME
123  * @implicit_qos_work: work structure used for deferring implicit QoS work
124  *	from softirq context to thread context
125  * @magic: magic number used to verify that this is a valid context when
126  *	referenced anonymously
127  * @is_inactivity_timer_running: true if inactivity timer is running
128  * @ts_id: identifier which gets used at time of DEL request
129  */
130 struct hdd_wmm_qos_context {
131 	struct list_head node;
132 	uint32_t handle;
133 	uint32_t flow_id;
134 	struct hdd_adapter *adapter;
135 	sme_ac_enum_type ac_type;
136 	hdd_wlan_wmm_status_e status;
137 	struct work_struct implicit_qos_work;
138 	uint32_t magic;
139 	bool is_inactivity_timer_running;
140 	uint8_t ts_id;
141 };
142 
143 /**
144  * struct hdd_wmm_ac_status - WMM related per-AC state & status info
145  * @is_access_required: does the AP require access to this AC?
146  * @is_access_needed: does the worker thread need to acquire access to
147  *	this AC?
148  * @is_access_pending: is implicit QoS negotiation currently taking place?
149  * @has_access_failed: has implicit QoS negotiation already failed?
150  * @was_access_granted: has implicit QoS negotiation already succeeded?
151  * @is_access_allowed: is access to this AC allowed, either because we
152  *	are not doing WMM, we are not doing implicit QoS, implicit QoS has
153  *	completed, or explicit QoS has completed?
154  * @is_tspec_valid: is the tspec valid?
155  * @is_uapsd_info_valid: are the UAPSD-related fields valid?
156  * @tspec: current (possibly aggregate) Tspec for this AC
157  * @is_uapsd_enabled: is UAPSD enabled on this AC?
158  * @uapsd_service_interval: service interval for this AC
159  * @uapsd_suspension_interval: suspension interval for this AC
160  * @uapsd_direction: direction for this AC
161  * @inactivity_time: inactivity time for this AC
162  * @last_traffic_count: TX counter used for inactivity detection
163  * @inactivity_timer: timer used for inactivity detection
164  */
165 struct hdd_wmm_ac_status {
166 	bool is_access_required;
167 	bool is_access_needed;
168 	bool is_access_pending;
169 	bool has_access_failed;
170 	bool was_access_granted;
171 	bool is_access_allowed;
172 	bool is_tspec_valid;
173 	bool is_uapsd_info_valid;
174 	struct sme_qos_wmmtspecinfo tspec;
175 	bool is_uapsd_enabled;
176 	uint32_t uapsd_service_interval;
177 	uint32_t uapsd_suspension_interval;
178 	enum sme_qos_wmm_dir_type uapsd_direction;
179 
180 #ifdef FEATURE_WLAN_ESE
181 	uint32_t inactivity_time;
182 	uint32_t last_traffic_count;
183 	qdf_mc_timer_t inactivity_timer;
184 #endif
185 };
186 
187 /**
188  * struct hdd_wmm_status - WMM status maintained per-adapter
189  * @context_list: list of WMM contexts active on the adapter
190  * @mutex: mutex used for exclusive access to this adapter's WMM status
191  * @ac_status: per-AC WMM status
192  * @qap: is this connected to a QoS-enabled AP?
193  * @qos_connection: is this a QoS connection?
194  */
195 struct hdd_wmm_status {
196 	struct list_head context_list;
197 	struct mutex mutex;
198 	struct hdd_wmm_ac_status ac_status[WLAN_MAX_AC];
199 	bool qap;
200 	bool qos_connection;
201 };
202 
203 extern const uint8_t hdd_qdisc_ac_to_tl_ac[];
204 extern const uint8_t hdd_wmm_up_to_ac_map[];
205 extern const uint8_t hdd_linux_up_to_ac_map[];
206 
207 /**
208  * hdd_wmmps_helper() - Function to set uapsd psb dynamically
209  *
210  * @adapter: [in] pointer to adapter structure
211  * @ptr: [in] pointer to command buffer
212  *
213  * Return: Zero on success, appropriate error on failure.
214  */
215 int hdd_wmmps_helper(struct hdd_adapter *adapter, uint8_t *ptr);
216 
217 /**
218  * hdd_send_dscp_up_map_to_fw() - send dscp to up map to FW
219  * @adapter : [in]  pointer to Adapter context
220  *
221  * This function will send the WMM DSCP configuration of an
222  * adapter to FW.
223  *
224  * Return: QDF_STATUS enumeration
225  */
226 QDF_STATUS hdd_send_dscp_up_map_to_fw(struct hdd_adapter *adapter);
227 
228 /**
229  * hdd_wmm_dscp_initial_state() - initialize the WMM DSCP configuration
230  * @adapter : [in]  pointer to Adapter context
231  *
232  * This function will initialize the WMM DSCP configuration of an
233  * adapter to an initial state.  The configuration can later be
234  * overwritten via application APIs or via QoS Map sent OTA.
235  *
236  * Return: QDF_STATUS enumeration
237  */
238 QDF_STATUS hdd_wmm_dscp_initial_state(struct hdd_adapter *adapter);
239 
240 /**
241  * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter
242  * @adapter: [in]  pointer to Adapter context
243  *
244  * This function will initialize the WMM configuration and status of an
245  * adapter to an initial state.  The configuration can later be
246  * overwritten via application APIs
247  *
248  * Return: QDF_STATUS enumeration
249  */
250 QDF_STATUS hdd_wmm_adapter_init(struct hdd_adapter *adapter);
251 
252 /**
253  * hdd_wmm_adapter_close() - WMM close function
254  * @adapter: [in]  pointer to adapter context
255  *
256  * Function which will perform any necessary work to to clean up the
257  * WMM functionality prior to the kernel module unload.
258  *
259  * Return: QDF_STATUS enumeration
260  */
261 QDF_STATUS hdd_wmm_adapter_close(struct hdd_adapter *adapter);
262 
263 /**
264  * hdd_select_queue() - Return queue to be used.
265  * @dev:	Pointer to the WLAN device.
266  * @skb:	Pointer to OS packet (sk_buff).
267  * @sb_dev:     Pointer to subordinate device (unused)
268  *
269  * This function is registered with the Linux OS for network
270  * core to decide which queue to use for the skb.
271  *
272  * Return: Qdisc queue index.
273  */
274 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
275 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
276 			  struct net_device *sb_dev);
277 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
278 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
279 			  struct net_device *sb_dev,
280 			  select_queue_fallback_t fallback);
281 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
282 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
283 			  void *accel_priv, select_queue_fallback_t fallback);
284 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
285 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb,
286 			  void *accel_priv);
287 #else
288 uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb);
289 #endif
290 
291 /**
292  * hdd_wmm_select_queue() - Function which will classify the packet
293  *       according to linux qdisc expectation.
294  *
295  * @dev: [in] pointer to net_device structure
296  * @skb: [in] pointer to os packet
297  *
298  * Return: Qdisc queue index
299  */
300 uint16_t hdd_wmm_select_queue(struct net_device *dev,
301 			      struct sk_buff *skb);
302 
303 /**
304  * hdd_wmm_acquire_access_required() - Function which will determine
305  * acquire admittance for a WMM AC is required or not based on psb configuration
306  * done in framework
307  *
308  * @adapter: [in] pointer to adapter structure
309  * @ac_type: [in] WMM AC type of OS packet
310  *
311  * Return: void
312  */
313 void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter,
314 				     sme_ac_enum_type ac_type);
315 
316 /**
317  * hdd_wmm_acquire_access() - Function which will attempt to acquire
318  * admittance for a WMM AC
319  *
320  * @adapter: [in]  pointer to adapter context
321  * @ac_type: [in]  WMM AC type of OS packet
322  * @granted: [out] pointer to bool flag when indicates if access
323  *	      has been granted or not
324  *
325  * Return: QDF_STATUS enumeration
326  */
327 QDF_STATUS hdd_wmm_acquire_access(struct hdd_adapter *adapter,
328 				  sme_ac_enum_type ac_type, bool *granted);
329 
330 /**
331  * hdd_wmm_assoc() - Function which will handle the housekeeping
332  * required by WMM when association takes place
333  *
334  * @adapter:  pointer to adapter context
335  * @is_reassoc: is this reassoc scenario
336  * @uapsd_mask : Negotiated uapsd msk
337  *
338  * Return: QDF_STATUS enumeration
339  */
340 QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter,
341 			 bool is_reassoc, uint8_t uapsd_mask);
342 
343 /**
344  * hdd_wmm_connect() - Function which will handle the housekeeping
345  * required by WMM when a connection is established
346  *
347  * @adapter : [in]  pointer to adapter context
348  * @roam_info: [in]  pointer to roam information
349  * @bss_type : [in]  type of BSS
350  *
351  * Return: QDF_STATUS enumeration
352  */
353 QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter,
354 			   struct csr_roam_info *roam_info,
355 			   eCsrRoamBssType bss_type);
356 
357 /**
358  * hdd_wmm_is_active() - Function which will determine if WMM is
359  * active on the current connection
360  *
361  * @adapter: [in]  pointer to adapter context
362  *
363  * Return: true if WMM is enabled, false if WMM is not enabled
364  */
365 bool hdd_wmm_is_active(struct hdd_adapter *adapter);
366 
367 /**
368  * hdd_wmm_is_acm_allowed() - Function which will determine if WMM is
369  * active on the current connection
370  *
371  * @vdev_id: vdev id
372  *
373  * Return: true if WMM is enabled, false if WMM is not enabled
374  */
375 bool hdd_wmm_is_acm_allowed(uint8_t vdev_id);
376 
377 
378 /**
379  * hdd_wmm_addts() - Function which will add a traffic spec at the
380  * request of an application
381  *
382  * @adapter  : [in]  pointer to adapter context
383  * @handle    : [in]  handle to uniquely identify a TS
384  * @tspec    : [in]  pointer to the traffic spec
385  *
386  * Return: HDD_WLAN_WMM_STATUS_*
387  */
388 hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter,
389 				    uint32_t handle,
390 				    struct sme_qos_wmmtspecinfo *tspec);
391 
392 /**
393  * hdd_wmm_delts() - Function which will delete a traffic spec at the
394  * request of an application
395  *
396  * @adapter: [in]  pointer to adapter context
397  * @handle: [in]  handle to uniquely identify a TS
398  *
399  * Return: HDD_WLAN_WMM_STATUS_*
400  */
401 hdd_wlan_wmm_status_e hdd_wmm_delts(struct hdd_adapter *adapter,
402 				    uint32_t handle);
403 
404 /**
405  * hdd_wmm_checkts() - Function which will return the status of a traffic
406  * spec at the request of an application
407  *
408  * @adapter: [in]  pointer to adapter context
409  * @handle: [in]  handle to uniquely identify a TS
410  *
411  * Return: HDD_WLAN_WMM_STATUS_*
412  */
413 hdd_wlan_wmm_status_e hdd_wmm_checkts(struct hdd_adapter *adapter,
414 				      uint32_t handle);
415 /**
416  * hdd_wmm_adapter_clear() - Function which will clear the WMM status
417  * for all the ACs
418  *
419  * @adapter: [in]  pointer to Adapter context
420  *
421  * Return: QDF_STATUS enumeration
422  */
423 QDF_STATUS hdd_wmm_adapter_clear(struct hdd_adapter *adapter);
424 
425 void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter);
426 
427 extern const struct nla_policy
428 config_tspec_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX + 1];
429 
430 /**
431  * wlan_hdd_cfg80211_config_tspec() - config tpsec
432  * @wiphy: pointer to wireless wiphy structure.
433  * @wdev: pointer to wireless_dev structure.
434  * @data: pointer to config tspec command parameters.
435  * @data_len: the length in byte of config tspec command parameters.
436  *
437  * Return: An error code or 0 on success.
438  */
439 int wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy,
440 				   struct wireless_dev *wdev,
441 				   const void *data, int data_len);
442 #ifdef QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES
443 /**
444  * hdd_wmm_classify_pkt_cb() - Call back to identify critical packets
445  * @adapter: adapter for which callback is called
446  * @nbuf: skb for which callback is called
447  *
448  * Callback used by intrabss forwarding path to identify critical packets.
449  * QDF_NBUF_CB_TX_EXTRA_IS_CRITICAL is marked 1 for such packets.
450  * The function also populates sb->priority for these packets.
451  * skb->priority is used as TID for these frames during TX.
452  *
453  * Return: None
454  */
455 void hdd_wmm_classify_pkt_cb(void *adapter,
456 			     qdf_nbuf_t nbuf);
457 #else
458 static inline
hdd_wmm_classify_pkt_cb(void * adapter,qdf_nbuf_t nbuf)459 void hdd_wmm_classify_pkt_cb(void *adapter,
460 			     qdf_nbuf_t nbuf)
461 {
462 }
463 #endif
464 
465 #define FEATURE_WMM_COMMANDS						\
466 {									\
467 	.info.vendor_id = QCA_NL80211_VENDOR_ID,			\
468 	.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC,		\
469 	.flags = WIPHY_VENDOR_CMD_NEED_WDEV |				\
470 		WIPHY_VENDOR_CMD_NEED_NETDEV |				\
471 		WIPHY_VENDOR_CMD_NEED_RUNNING,				\
472 	.doit = wlan_hdd_cfg80211_config_tspec,				\
473 	vendor_command_policy(config_tspec_policy,			\
474 			      QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX)	\
475 },
476 
477 #endif /* #ifndef _WLAN_HDD_WMM_H */
478