1 /*
2 * Copyright (c) 2017-2020 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: Implements gtk offload feature API's
21 */
22
23 #include "wlan_pmo_gtk.h"
24 #include "wlan_pmo_tgt_api.h"
25 #include "wlan_pmo_main.h"
26 #include "wlan_pmo_obj_mgmt_public_struct.h"
27
pmo_core_cache_gtk_req_in_vdev_priv(struct wlan_objmgr_vdev * vdev,struct pmo_gtk_req * gtk_req)28 static QDF_STATUS pmo_core_cache_gtk_req_in_vdev_priv(
29 struct wlan_objmgr_vdev *vdev,
30 struct pmo_gtk_req *gtk_req)
31 {
32 struct pmo_vdev_priv_obj *vdev_ctx;
33 QDF_STATUS status;
34 struct qdf_mac_addr peer_bssid;
35
36 vdev_ctx = pmo_vdev_get_priv(vdev);
37
38 status = pmo_get_vdev_bss_peer_mac_addr(vdev, &peer_bssid);
39 if (status != QDF_STATUS_SUCCESS)
40 return status;
41
42 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
43 qdf_mem_copy(&vdev_ctx->vdev_gtk_req, gtk_req,
44 sizeof(vdev_ctx->vdev_gtk_req));
45 qdf_mem_copy(&vdev_ctx->vdev_gtk_req.bssid,
46 &peer_bssid, QDF_MAC_ADDR_SIZE);
47 vdev_ctx->vdev_gtk_req.flags = PMO_GTK_OFFLOAD_ENABLE;
48 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
49
50 return QDF_STATUS_SUCCESS;
51 }
52
pmo_core_flush_gtk_req_from_vdev_priv(struct wlan_objmgr_vdev * vdev)53 static QDF_STATUS pmo_core_flush_gtk_req_from_vdev_priv(
54 struct wlan_objmgr_vdev *vdev)
55 {
56 struct pmo_vdev_priv_obj *vdev_ctx;
57
58 vdev_ctx = pmo_vdev_get_priv(vdev);
59
60 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
61 qdf_mem_zero(&vdev_ctx->vdev_gtk_req, sizeof(vdev_ctx->vdev_gtk_req));
62 vdev_ctx->vdev_gtk_req.flags = PMO_GTK_OFFLOAD_DISABLE;
63 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
64
65 return QDF_STATUS_SUCCESS;
66 }
67
pmo_core_do_enable_gtk_offload(struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx,struct pmo_gtk_req * op_gtk_req)68 static QDF_STATUS pmo_core_do_enable_gtk_offload(
69 struct wlan_objmgr_vdev *vdev,
70 struct pmo_vdev_priv_obj *vdev_ctx,
71 struct pmo_gtk_req *op_gtk_req)
72 {
73 QDF_STATUS status = QDF_STATUS_SUCCESS;
74 uint8_t vdev_id;
75 enum QDF_OPMODE op_mode;
76
77 op_mode = pmo_get_vdev_opmode(vdev);
78 if (QDF_NDI_MODE == op_mode) {
79 pmo_debug("gtk offload is not supported in NaN mode");
80 return QDF_STATUS_E_INVAL;
81 }
82
83 if (!pmo_core_is_vdev_supports_offload(vdev)) {
84 pmo_debug("vdev in invalid opmode for gtk offload %d",
85 pmo_get_vdev_opmode(vdev));
86 return QDF_STATUS_E_INVAL;
87 }
88
89 if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS)
90 return QDF_STATUS_E_INVAL;
91
92 vdev_id = pmo_vdev_get_id(vdev);
93
94 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
95 qdf_mem_copy(op_gtk_req, &vdev_ctx->vdev_gtk_req,
96 sizeof(*op_gtk_req));
97 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
98
99 if ((op_gtk_req->flags == PMO_GTK_OFFLOAD_ENABLE) &&
100 (qdf_atomic_read(&vdev_ctx->gtk_err_enable) == 1)) {
101 pmo_debug("GTK Offload already enabled, Disabling vdev_id: %d",
102 vdev_id);
103 op_gtk_req->flags = PMO_GTK_OFFLOAD_DISABLE;
104 status = pmo_tgt_send_gtk_offload_req(vdev, op_gtk_req);
105 if (status != QDF_STATUS_SUCCESS) {
106 pmo_err("Failed to disable GTK Offload");
107 goto out;
108 }
109 pmo_debug("Enable GTK Offload again with updated inputs");
110 op_gtk_req->flags = PMO_GTK_OFFLOAD_ENABLE;
111 }
112
113 status = pmo_tgt_send_gtk_offload_req(vdev, op_gtk_req);
114 out:
115
116 return status;
117 }
118
pmo_core_is_gtk_enabled_in_fwr(struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)119 static QDF_STATUS pmo_core_is_gtk_enabled_in_fwr(
120 struct wlan_objmgr_vdev *vdev,
121 struct pmo_vdev_priv_obj *vdev_ctx)
122 {
123 QDF_STATUS status;
124 struct qdf_mac_addr peer_bssid;
125
126 if (!pmo_core_is_vdev_supports_offload(vdev)) {
127 pmo_debug("vdev in invalid opmode for gtk offload enable %d",
128 pmo_get_vdev_opmode(vdev));
129 return QDF_STATUS_E_INVAL;
130 }
131
132 if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS)
133 return QDF_STATUS_E_INVAL;
134
135 status = pmo_get_vdev_bss_peer_mac_addr(vdev,
136 &peer_bssid);
137 if (status != QDF_STATUS_SUCCESS)
138 return QDF_STATUS_E_INVAL;
139
140 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
141 if (qdf_mem_cmp(&vdev_ctx->vdev_gtk_req.bssid,
142 &peer_bssid, QDF_MAC_ADDR_SIZE)) {
143 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
144 pmo_err("cache request mac:"QDF_MAC_ADDR_FMT", peer mac:"QDF_MAC_ADDR_FMT" are not same",
145 QDF_MAC_ADDR_REF(vdev_ctx->vdev_gtk_req.bssid.bytes),
146 QDF_MAC_ADDR_REF(peer_bssid.bytes));
147 return QDF_STATUS_E_INVAL;
148 }
149
150 if (vdev_ctx->vdev_gtk_req.flags != PMO_GTK_OFFLOAD_ENABLE) {
151 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
152 pmo_err("gtk flag is disabled hence no gtk rsp required");
153 return QDF_STATUS_E_INVAL;
154 }
155 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
156
157 return QDF_STATUS_SUCCESS;
158 }
159
pmo_core_do_disable_gtk_offload(struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx,struct pmo_gtk_req * op_gtk_req)160 static QDF_STATUS pmo_core_do_disable_gtk_offload(
161 struct wlan_objmgr_vdev *vdev,
162 struct pmo_vdev_priv_obj *vdev_ctx,
163 struct pmo_gtk_req *op_gtk_req)
164 {
165 QDF_STATUS status = QDF_STATUS_SUCCESS;
166 enum QDF_OPMODE op_mode;
167
168 op_mode = pmo_get_vdev_opmode(vdev);
169 if (QDF_NDI_MODE == op_mode) {
170 pmo_debug("gtk offload is not supported in NaN mode");
171 return QDF_STATUS_E_INVAL;
172 }
173
174 status = pmo_core_is_gtk_enabled_in_fwr(vdev, vdev_ctx);
175 if (status != QDF_STATUS_SUCCESS)
176 return status;
177
178 op_gtk_req->flags = PMO_GTK_OFFLOAD_DISABLE;
179 status = pmo_tgt_send_gtk_offload_req(vdev, op_gtk_req);
180
181 return status;
182 }
183
pmo_core_cache_gtk_offload_req(struct wlan_objmgr_vdev * vdev,struct pmo_gtk_req * gtk_req)184 QDF_STATUS pmo_core_cache_gtk_offload_req(struct wlan_objmgr_vdev *vdev,
185 struct pmo_gtk_req *gtk_req)
186 {
187 QDF_STATUS status;
188 enum QDF_OPMODE opmode;
189 uint8_t vdev_id;
190
191 if (!gtk_req) {
192 pmo_err("gtk_req is NULL");
193 status = QDF_STATUS_E_INVAL;
194 goto out;
195 }
196
197 if (!vdev) {
198 pmo_err("vdev is NULL");
199 status = QDF_STATUS_E_INVAL;
200 goto out;
201 }
202
203 status = pmo_vdev_get_ref(vdev);
204 if (status != QDF_STATUS_SUCCESS)
205 goto out;
206
207 opmode = pmo_get_vdev_opmode(vdev);
208 vdev_id = pmo_vdev_get_id(vdev);
209 pmo_debug("vdev opmode: %d vdev_id: %d", opmode, vdev_id);
210 if (!pmo_core_is_vdev_supports_offload(vdev)) {
211 pmo_debug("vdev in invalid opmode for caching gtk request %d",
212 opmode);
213 status = QDF_STATUS_E_INVAL;
214 goto dec_ref;
215 }
216
217 status = pmo_core_cache_gtk_req_in_vdev_priv(vdev, gtk_req);
218 dec_ref:
219 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
220 out:
221
222 return status;
223 }
224
pmo_core_flush_gtk_offload_req(struct wlan_objmgr_vdev * vdev)225 QDF_STATUS pmo_core_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev)
226 {
227 enum QDF_OPMODE opmode;
228 uint8_t vdev_id;
229 QDF_STATUS status;
230
231 if (!vdev) {
232 pmo_err("psoc is NULL");
233 status = QDF_STATUS_E_INVAL;
234 goto out;
235 }
236
237 status = pmo_vdev_get_ref(vdev);
238 if (status != QDF_STATUS_SUCCESS)
239 goto out;
240
241 opmode = pmo_get_vdev_opmode(vdev);
242 vdev_id = pmo_vdev_get_id(vdev);
243 pmo_debug("vdev opmode: %d vdev_id: %d", opmode, vdev_id);
244 if (!pmo_core_is_vdev_supports_offload(vdev)) {
245 pmo_debug("vdev in invalid opmode for flushing gtk request %d",
246 opmode);
247 status = QDF_STATUS_E_INVAL;
248 goto dec_ref;
249 }
250
251 status = pmo_core_flush_gtk_req_from_vdev_priv(vdev);
252 dec_ref:
253 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
254 out:
255
256 return status;
257 }
258
pmo_core_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev * vdev)259 QDF_STATUS pmo_core_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev)
260 {
261 QDF_STATUS status;
262 struct pmo_vdev_priv_obj *vdev_ctx;
263 struct pmo_gtk_req *op_gtk_req = NULL;
264
265 pmo_enter();
266 if (!vdev) {
267 pmo_err("vdev is NULL");
268 status = QDF_STATUS_E_INVAL;
269 goto out;
270 }
271
272 status = pmo_vdev_get_ref(vdev);
273 if (status != QDF_STATUS_SUCCESS)
274 goto out;
275
276 vdev_ctx = pmo_vdev_get_priv(vdev);
277
278 op_gtk_req = qdf_mem_malloc(sizeof(*op_gtk_req));
279 if (!op_gtk_req) {
280 status = QDF_STATUS_E_INVAL;
281 goto dec_ref;
282 }
283 status = pmo_core_do_enable_gtk_offload(vdev, vdev_ctx, op_gtk_req);
284 dec_ref:
285 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
286 out:
287 if (op_gtk_req)
288 qdf_mem_free(op_gtk_req);
289 pmo_exit();
290
291 return status;
292 }
293
pmo_core_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev * vdev)294 QDF_STATUS pmo_core_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev)
295 {
296 QDF_STATUS status;
297 struct pmo_vdev_priv_obj *vdev_ctx;
298 struct pmo_gtk_req *op_gtk_req = NULL;
299
300 pmo_enter();
301 if (!vdev) {
302 pmo_err("vdev is NULL");
303 status = QDF_STATUS_E_INVAL;
304 goto out;
305 }
306
307 status = pmo_vdev_get_ref(vdev);
308 if (status != QDF_STATUS_SUCCESS)
309 goto out;
310
311 vdev_ctx = pmo_vdev_get_priv(vdev);
312
313 op_gtk_req = qdf_mem_malloc(sizeof(*op_gtk_req));
314 if (!op_gtk_req) {
315 status = QDF_STATUS_E_NOMEM;
316 goto dec_ref;
317 }
318
319 status = pmo_core_do_disable_gtk_offload(vdev, vdev_ctx, op_gtk_req);
320 dec_ref:
321 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
322 out:
323 if (op_gtk_req)
324 qdf_mem_free(op_gtk_req);
325 pmo_exit();
326
327 return status;
328 }
329
pmo_core_get_gtk_rsp(struct wlan_objmgr_vdev * vdev,struct pmo_gtk_rsp_req * gtk_rsp_req)330 QDF_STATUS pmo_core_get_gtk_rsp(struct wlan_objmgr_vdev *vdev,
331 struct pmo_gtk_rsp_req *gtk_rsp_req)
332 {
333 QDF_STATUS status = QDF_STATUS_SUCCESS;
334 struct pmo_vdev_priv_obj *vdev_ctx;
335
336 pmo_enter();
337 if (!gtk_rsp_req || !vdev) {
338 pmo_err("%s is null", !vdev ? "vdev":"gtk_rsp_req");
339 status = QDF_STATUS_E_INVAL;
340 goto out;
341 }
342
343 status = pmo_vdev_get_ref(vdev);
344 if (status != QDF_STATUS_SUCCESS)
345 goto out;
346
347 vdev_ctx = pmo_vdev_get_priv(vdev);
348
349 status = pmo_core_is_gtk_enabled_in_fwr(vdev, vdev_ctx);
350 if (status != QDF_STATUS_SUCCESS)
351 goto dec_ref;
352
353 /* cache gtk rsp request */
354 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
355 qdf_mem_copy(&vdev_ctx->vdev_gtk_rsp_req, gtk_rsp_req,
356 sizeof(vdev_ctx->vdev_gtk_rsp_req));
357 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
358 /* send cmd to fwr */
359 status = pmo_tgt_get_gtk_rsp(vdev);
360 dec_ref:
361 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID);
362 out:
363 pmo_exit();
364
365 return status;
366 }
367
368