1 /*
2  * Copyright (c) 2014 Qualcomm Atheros, Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "core.h"
18 #include "wmi-ops.h"
19 #include "debug.h"
20 
21 static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
22 					     char __user *user_buf,
23 					     size_t count, loff_t *ppos)
24 {
25 	struct ieee80211_sta *sta = file->private_data;
26 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
27 	struct ath10k *ar = arsta->arvif->ar;
28 	char buf[32];
29 	int len = 0;
30 
31 	mutex_lock(&ar->conf_mutex);
32 	len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",
33 			(arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?
34 			"auto" : "manual");
35 	mutex_unlock(&ar->conf_mutex);
36 
37 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
38 }
39 
40 static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,
41 					      const char __user *user_buf,
42 					      size_t count, loff_t *ppos)
43 {
44 	struct ieee80211_sta *sta = file->private_data;
45 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
46 	struct ath10k *ar = arsta->arvif->ar;
47 	u32 aggr_mode;
48 	int ret;
49 
50 	if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
51 		return -EINVAL;
52 
53 	if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)
54 		return -EINVAL;
55 
56 	mutex_lock(&ar->conf_mutex);
57 	if ((ar->state != ATH10K_STATE_ON) ||
58 	    (aggr_mode == arsta->aggr_mode)) {
59 		ret = count;
60 		goto out;
61 	}
62 
63 	ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
64 	if (ret) {
65 		ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);
66 		goto out;
67 	}
68 
69 	arsta->aggr_mode = aggr_mode;
70 out:
71 	mutex_unlock(&ar->conf_mutex);
72 	return ret;
73 }
74 
75 static const struct file_operations fops_aggr_mode = {
76 	.read = ath10k_dbg_sta_read_aggr_mode,
77 	.write = ath10k_dbg_sta_write_aggr_mode,
78 	.open = simple_open,
79 	.owner = THIS_MODULE,
80 	.llseek = default_llseek,
81 };
82 
83 static ssize_t ath10k_dbg_sta_write_addba(struct file *file,
84 					  const char __user *user_buf,
85 					  size_t count, loff_t *ppos)
86 {
87 	struct ieee80211_sta *sta = file->private_data;
88 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
89 	struct ath10k *ar = arsta->arvif->ar;
90 	u32 tid, buf_size;
91 	int ret;
92 	char buf[64];
93 
94 	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
95 
96 	/* make sure that buf is null terminated */
97 	buf[sizeof(buf) - 1] = '\0';
98 
99 	ret = sscanf(buf, "%u %u", &tid, &buf_size);
100 	if (ret != 2)
101 		return -EINVAL;
102 
103 	/* Valid TID values are 0 through 15 */
104 	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
105 		return -EINVAL;
106 
107 	mutex_lock(&ar->conf_mutex);
108 	if ((ar->state != ATH10K_STATE_ON) ||
109 	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
110 		ret = count;
111 		goto out;
112 	}
113 
114 	ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
115 				    tid, buf_size);
116 	if (ret) {
117 		ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
118 			    arsta->arvif->vdev_id, sta->addr, tid, buf_size);
119 	}
120 
121 	ret = count;
122 out:
123 	mutex_unlock(&ar->conf_mutex);
124 	return ret;
125 }
126 
127 static const struct file_operations fops_addba = {
128 	.write = ath10k_dbg_sta_write_addba,
129 	.open = simple_open,
130 	.owner = THIS_MODULE,
131 	.llseek = default_llseek,
132 };
133 
134 static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,
135 					       const char __user *user_buf,
136 					       size_t count, loff_t *ppos)
137 {
138 	struct ieee80211_sta *sta = file->private_data;
139 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
140 	struct ath10k *ar = arsta->arvif->ar;
141 	u32 tid, status;
142 	int ret;
143 	char buf[64];
144 
145 	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
146 
147 	/* make sure that buf is null terminated */
148 	buf[sizeof(buf) - 1] = '\0';
149 
150 	ret = sscanf(buf, "%u %u", &tid, &status);
151 	if (ret != 2)
152 		return -EINVAL;
153 
154 	/* Valid TID values are 0 through 15 */
155 	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
156 		return -EINVAL;
157 
158 	mutex_lock(&ar->conf_mutex);
159 	if ((ar->state != ATH10K_STATE_ON) ||
160 	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
161 		ret = count;
162 		goto out;
163 	}
164 
165 	ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
166 					tid, status);
167 	if (ret) {
168 		ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
169 			    arsta->arvif->vdev_id, sta->addr, tid, status);
170 	}
171 	ret = count;
172 out:
173 	mutex_unlock(&ar->conf_mutex);
174 	return ret;
175 }
176 
177 static const struct file_operations fops_addba_resp = {
178 	.write = ath10k_dbg_sta_write_addba_resp,
179 	.open = simple_open,
180 	.owner = THIS_MODULE,
181 	.llseek = default_llseek,
182 };
183 
184 static ssize_t ath10k_dbg_sta_write_delba(struct file *file,
185 					  const char __user *user_buf,
186 					  size_t count, loff_t *ppos)
187 {
188 	struct ieee80211_sta *sta = file->private_data;
189 	struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
190 	struct ath10k *ar = arsta->arvif->ar;
191 	u32 tid, initiator, reason;
192 	int ret;
193 	char buf[64];
194 
195 	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
196 
197 	/* make sure that buf is null terminated */
198 	buf[sizeof(buf) - 1] = '\0';
199 
200 	ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
201 	if (ret != 3)
202 		return -EINVAL;
203 
204 	/* Valid TID values are 0 through 15 */
205 	if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
206 		return -EINVAL;
207 
208 	mutex_lock(&ar->conf_mutex);
209 	if ((ar->state != ATH10K_STATE_ON) ||
210 	    (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
211 		ret = count;
212 		goto out;
213 	}
214 
215 	ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
216 				    tid, initiator, reason);
217 	if (ret) {
218 		ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
219 			    arsta->arvif->vdev_id, sta->addr, tid, initiator,
220 			    reason);
221 	}
222 	ret = count;
223 out:
224 	mutex_unlock(&ar->conf_mutex);
225 	return ret;
226 }
227 
228 static const struct file_operations fops_delba = {
229 	.write = ath10k_dbg_sta_write_delba,
230 	.open = simple_open,
231 	.owner = THIS_MODULE,
232 	.llseek = default_llseek,
233 };
234 
235 void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
236 			    struct ieee80211_sta *sta, struct dentry *dir)
237 {
238 	debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta,
239 			    &fops_aggr_mode);
240 	debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
241 	debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
242 	debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
243 }
244