blob: 73fc024481d4617ab419d40337c723654febaff4 [file] [log] [blame]
Mukul Sharmad75a6672017-06-22 15:40:53 +05301/*
Dustin Brownb2cd2e02018-03-15 11:59:45 -07002 * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
Jeff Johnsonb4c29962017-10-07 19:35:14 -07003 *
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 */
Dustin Brownb2cd2e02018-03-15 11:59:45 -070018
Mukul Sharmad75a6672017-06-22 15:40:53 +053019/**
20 * DOC: Implements ns offload feature API's
21 */
22
23#include "wlan_pmo_ns.h"
24#include "wlan_pmo_tgt_api.h"
25#include "wlan_pmo_main.h"
26#include "wlan_pmo_obj_mgmt_public_struct.h"
27
28static void pmo_core_fill_ns_addr(struct pmo_ns_offload_params *request,
Dustin Brownb2cd2e02018-03-15 11:59:45 -070029 struct pmo_ns_req *ns_req)
Mukul Sharmad75a6672017-06-22 15:40:53 +053030{
31 int i;
32
33 for (i = 0; i < ns_req->count; i++) {
34 /*
35 * Filling up the request structure
36 * Filling the selfIPv6Addr with solicited address
37 * A Solicited-Node multicast address is created by
38 * taking the last 24 bits of a unicast or anycast
39 * address and appending them to the prefix
40 *
41 * FF02:0000:0000:0000:0000:0001:FFXX:XXXX
42 *
43 * here XX is the unicast/anycast bits
44 */
45 request->self_ipv6_addr[i][0] = 0xFF;
46 request->self_ipv6_addr[i][1] = 0x02;
47 request->self_ipv6_addr[i][11] = 0x01;
48 request->self_ipv6_addr[i][12] = 0xFF;
49 request->self_ipv6_addr[i][13] =
50 ns_req->ipv6_addr[i][13];
51 request->self_ipv6_addr[i][14] =
52 ns_req->ipv6_addr[i][14];
53 request->self_ipv6_addr[i][15] =
54 ns_req->ipv6_addr[i][15];
55 request->slot_idx = i;
56 qdf_mem_copy(&request->target_ipv6_addr[i],
57 &ns_req->ipv6_addr[i][0], PMO_MAC_IPV6_ADDR_LEN);
58
59 request->target_ipv6_addr_valid[i] =
60 PMO_IPV6_ADDR_VALID;
61 request->target_ipv6_addr_ac_type[i] =
62 ns_req->ipv6_addr_type[i];
63
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +053064 request->scope[i] = ns_req->scope[i];
65
Rajeev Kumar08f67ca2017-09-25 17:06:51 -070066 pmo_debug("NSoffload solicitIp: %pI6 targetIp: %pI6 Index: %d",
Mukul Sharmad75a6672017-06-22 15:40:53 +053067 &request->self_ipv6_addr[i],
68 &request->target_ipv6_addr[i], i);
69 }
70}
71
72static QDF_STATUS pmo_core_cache_ns_in_vdev_priv(
73 struct pmo_ns_req *ns_req,
74 struct wlan_objmgr_vdev *vdev)
75{
76 QDF_STATUS status = QDF_STATUS_SUCCESS;
77 struct pmo_vdev_priv_obj *vdev_ctx;
78 struct pmo_ns_offload_params request;
79 struct wlan_objmgr_peer *peer;
80
Dustin Brownb2cd2e02018-03-15 11:59:45 -070081 pmo_enter();
Mukul Sharmad75a6672017-06-22 15:40:53 +053082
83 vdev_ctx = pmo_vdev_get_priv(vdev);
84
85 qdf_mem_zero(&request, sizeof(request));
86 pmo_core_fill_ns_addr(&request, ns_req);
87
88 request.enable = PMO_OFFLOAD_ENABLE;
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +053089 request.is_offload_applied = false;
Mukul Sharmad75a6672017-06-22 15:40:53 +053090 qdf_mem_copy(&request.self_macaddr.bytes,
91 wlan_vdev_mlme_get_macaddr(vdev),
92 QDF_MAC_ADDR_SIZE);
93
94 /* set number of ns offload address count */
95 request.num_ns_offload_count = ns_req->count;
96
97 peer = wlan_vdev_get_bsspeer(vdev);
98 if (!peer) {
99 pmo_err("peer is null");
100 status = QDF_STATUS_E_INVAL;
101 goto out;
102 }
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700103 pmo_debug("vdev self mac addr: %pM bss peer mac addr: %pM",
Mukul Sharmad75a6672017-06-22 15:40:53 +0530104 wlan_vdev_mlme_get_macaddr(vdev),
105 wlan_peer_get_macaddr(peer));
106 /* get peer and peer mac accdress aka ap mac address */
107 qdf_mem_copy(&request.bssid,
108 wlan_peer_get_macaddr(peer),
109 QDF_MAC_ADDR_SIZE);
110 /* cache ns request */
111 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
112 qdf_mem_copy(&vdev_ctx->vdev_ns_req, &request,
113 sizeof(vdev_ctx->vdev_ns_req));
114 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
115out:
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700116 pmo_exit();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530117
118 return status;
119}
120
121static QDF_STATUS pmo_core_flush_ns_from_vdev_priv(
122 struct wlan_objmgr_vdev *vdev)
123{
124 struct pmo_vdev_priv_obj *vdev_ctx;
125
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700126 pmo_enter();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530127
128 vdev_ctx = pmo_vdev_get_priv(vdev);
129
130 /* clear ns request */
131 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
132 qdf_mem_zero(&vdev_ctx->vdev_ns_req, sizeof(vdev_ctx->vdev_ns_req));
133 vdev_ctx->vdev_ns_req.enable = PMO_OFFLOAD_DISABLE;
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530134 vdev_ctx->vdev_ns_req.is_offload_applied = false;
Mukul Sharmad75a6672017-06-22 15:40:53 +0530135 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
136
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700137 pmo_exit();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530138
139 return QDF_STATUS_SUCCESS;
140}
141
142static QDF_STATUS pmo_core_do_enable_ns_offload(struct wlan_objmgr_vdev *vdev,
143 uint8_t vdev_id, enum pmo_offload_trigger trigger)
144{
145 QDF_STATUS status = QDF_STATUS_SUCCESS;
146 struct pmo_psoc_priv_obj *psoc_ctx;
147 struct pmo_vdev_priv_obj *vdev_ctx;
148
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700149 pmo_enter();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530150
151 vdev_ctx = pmo_vdev_get_priv(vdev);
152
153 psoc_ctx = vdev_ctx->pmo_psoc_ctx;
154 if (!psoc_ctx) {
155 pmo_err("psoc_ctx is NULL");
156 status = QDF_STATUS_E_INVAL;
157 goto out;
158 }
159
160 switch (trigger) {
161 case pmo_ipv6_change_notify:
162 case pmo_ns_offload_dynamic_update:
163 if (!psoc_ctx->psoc_cfg.active_mode_offload) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700164 pmo_debug("active offload is disabled, skip in mode:%d",
Mukul Sharmad75a6672017-06-22 15:40:53 +0530165 trigger);
Dustin Brown867ce6d2018-07-19 16:03:33 -0700166 status = QDF_STATUS_SUCCESS;
Mukul Sharmad75a6672017-06-22 15:40:53 +0530167 goto out;
168 }
169 /* enable arp when active offload is true (ipv6 notifier) */
170 status = pmo_tgt_enable_ns_offload_req(vdev, vdev_id);
171 break;
172 case pmo_apps_suspend:
173 if (psoc_ctx->psoc_cfg.active_mode_offload) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700174 pmo_debug("active offload is enabled, skip in mode: %d",
Mukul Sharmad75a6672017-06-22 15:40:53 +0530175 trigger);
Dustin Brown867ce6d2018-07-19 16:03:33 -0700176 status = QDF_STATUS_SUCCESS;
Mukul Sharmad75a6672017-06-22 15:40:53 +0530177 goto out;
178 }
179 /* enable arp when active offload is false (apps suspend) */
180 status = pmo_tgt_enable_ns_offload_req(vdev, vdev_id);
181 break;
182 default:
183 status = QDF_STATUS_E_INVAL;
184 pmo_err("invalid pmo trigger");
185 break;
186 }
187out:
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700188 pmo_exit();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530189
190 return status;
191}
192
193static QDF_STATUS pmo_core_do_disable_ns_offload(struct wlan_objmgr_vdev *vdev,
194 uint8_t vdev_id, enum pmo_offload_trigger trigger)
195{
196 QDF_STATUS status = QDF_STATUS_SUCCESS;
197 struct pmo_psoc_priv_obj *psoc_ctx;
198
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700199 pmo_enter();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530200
201 psoc_ctx = pmo_vdev_get_psoc_priv(vdev);
202
203 switch (trigger) {
204 case pmo_ipv6_change_notify:
205 case pmo_ns_offload_dynamic_update:
206 if (!psoc_ctx->psoc_cfg.active_mode_offload) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700207 pmo_debug("active offload is disabled, skip in mode:%d",
Mukul Sharmad75a6672017-06-22 15:40:53 +0530208 trigger);
209 status = QDF_STATUS_E_INVAL;
210 goto out;
211 }
212 /* config ns when active offload is enable */
213 status = pmo_tgt_disable_ns_offload_req(vdev, vdev_id);
214 break;
215 case pmo_apps_resume:
216 if (psoc_ctx->psoc_cfg.active_mode_offload) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700217 pmo_debug("active offload is enabled, skip in mode: %d",
Mukul Sharmad75a6672017-06-22 15:40:53 +0530218 trigger);
219 status = QDF_STATUS_E_INVAL;
220 goto out;
221 }
222 /* config arp/ns when active offload is disable */
223 status = pmo_tgt_disable_ns_offload_req(vdev, vdev_id);
224 break;
225 default:
226 status = QDF_STATUS_E_INVAL;
227 pmo_err("invalid pmo trigger");
228 break;
229 }
230out:
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700231 pmo_exit();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530232
233 return status;
234}
235
236
237static QDF_STATUS pmo_core_ns_offload_sanity(struct wlan_objmgr_vdev *vdev)
238{
239 struct pmo_vdev_priv_obj *vdev_ctx;
240
241 vdev_ctx = pmo_vdev_get_priv(vdev);
242
243 if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_static) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700244 pmo_debug("ns offload statically disable");
Mukul Sharmad75a6672017-06-22 15:40:53 +0530245 return QDF_STATUS_E_INVAL;
246 }
247
248 if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700249 pmo_debug("ns offload dynamically disable");
Mukul Sharmad75a6672017-06-22 15:40:53 +0530250 return QDF_STATUS_E_INVAL;
251 }
252
253 if (!pmo_core_is_vdev_supports_offload(vdev)) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700254 pmo_debug("vdev in invalid opmode for ns offload %d",
Mukul Sharmad75a6672017-06-22 15:40:53 +0530255 pmo_get_vdev_opmode(vdev));
256 return QDF_STATUS_E_INVAL;
257 }
258
259 if (pmo_core_is_vdev_connected(vdev) == false)
260 return QDF_STATUS_E_INVAL;
261
262 return QDF_STATUS_SUCCESS;
263}
264
265QDF_STATUS pmo_core_cache_ns_offload_req(
266 struct pmo_ns_req *ns_req)
267{
268 QDF_STATUS status;
269 struct wlan_objmgr_vdev *vdev;
270
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700271 pmo_enter();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530272 if (!ns_req) {
273 pmo_err("ns is NULL");
274 status = QDF_STATUS_E_INVAL;
275 goto out;
276 }
277
278 if (!ns_req->psoc) {
279 pmo_err("psoc is NULL");
280 status = QDF_STATUS_E_INVAL;
281 goto out;
282 }
283
284 vdev = pmo_psoc_get_vdev(ns_req->psoc, ns_req->vdev_id);
285 if (!vdev) {
286 pmo_err("vdev is NULL");
287 status = QDF_STATUS_E_INVAL;
288 goto out;
289 }
290
291 status = pmo_vdev_get_ref(vdev);
292 if (QDF_IS_STATUS_ERROR(status))
293 goto out;
294
295 status = pmo_core_ns_offload_sanity(vdev);
296 if (status != QDF_STATUS_SUCCESS)
297 goto dec_ref;
298
299 if (ns_req->count == 0) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700300 pmo_debug("skip ns offload caching as ns count is 0");
Mukul Sharmad75a6672017-06-22 15:40:53 +0530301 status = QDF_STATUS_E_INVAL;
302 goto dec_ref;
303 }
304
305 status = pmo_core_cache_ns_in_vdev_priv(ns_req, vdev);
306dec_ref:
307 pmo_vdev_put_ref(vdev);
308out:
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700309 pmo_exit();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530310
311 return status;
312}
313
314QDF_STATUS pmo_core_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev)
315{
316 QDF_STATUS status;
317 uint8_t vdev_id;
318
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700319 pmo_enter();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530320 if (!vdev) {
321 pmo_err("vdev is NULL");
322 status = QDF_STATUS_E_INVAL;
323 goto out;
324 }
325
326 status = pmo_vdev_get_ref(vdev);
327 if (status != QDF_STATUS_SUCCESS)
328 goto out;
329
330 status = pmo_core_ns_offload_sanity(vdev);
331 if (status != QDF_STATUS_SUCCESS)
332 goto dec_ref;
333
334 vdev_id = pmo_vdev_get_id(vdev);
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700335 pmo_debug("Flush ns offload on vdev id: %d vdev: %pK", vdev_id, vdev);
Mukul Sharmad75a6672017-06-22 15:40:53 +0530336
337 status = pmo_core_flush_ns_from_vdev_priv(vdev);
338dec_ref:
339 pmo_vdev_put_ref(vdev);
340out:
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700341 pmo_exit();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530342
343 return status;
344}
345
346QDF_STATUS pmo_core_enable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
347 enum pmo_offload_trigger trigger)
348{
349 QDF_STATUS status;
350 struct pmo_vdev_priv_obj *vdev_ctx;
351 uint8_t vdev_id;
352
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700353 pmo_enter();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530354 if (!vdev) {
355 pmo_err("vdev is NULL");
356 status = QDF_STATUS_E_INVAL;
357 goto out;
358 }
359
360 status = pmo_vdev_get_ref(vdev);
361 if (status != QDF_STATUS_SUCCESS)
362 goto out;
363
364 vdev_ctx = pmo_vdev_get_priv(vdev);
365
366 status = pmo_core_ns_offload_sanity(vdev);
367 if (status != QDF_STATUS_SUCCESS)
368 goto dec_ref;
369
370 if (trigger == pmo_ns_offload_dynamic_update) {
371 /*
372 * user disable ns offload using ioctl/vendor cmd dynamically.
373 */
374 vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic =
375 true;
376 goto skip_ns_dynamic_check;
377 }
378
379 if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700380 pmo_debug("ns offload dynamically disable");
Mukul Sharmad75a6672017-06-22 15:40:53 +0530381 status = QDF_STATUS_E_INVAL;
382 goto dec_ref;
383 }
384
385skip_ns_dynamic_check:
386 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
387 if (vdev_ctx->vdev_ns_req.num_ns_offload_count == 0) {
388 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700389 pmo_debug("skip ns offload enable as ns count is 0");
Mukul Sharmad75a6672017-06-22 15:40:53 +0530390 status = QDF_STATUS_E_INVAL;
391 goto out;
392 }
393 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
394
395 vdev_id = pmo_vdev_get_id(vdev);
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700396 pmo_debug("Enable ns offload in fwr vdev id: %d vdev: %pK trigger: %d",
Mukul Sharmad75a6672017-06-22 15:40:53 +0530397 vdev_id, vdev, trigger);
398 status = pmo_core_do_enable_ns_offload(vdev, vdev_id, trigger);
399dec_ref:
400 pmo_vdev_put_ref(vdev);
401out:
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700402 pmo_exit();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530403
404 return status;
405}
406
407QDF_STATUS pmo_core_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev,
408 enum pmo_offload_trigger trigger)
409{
410 QDF_STATUS status;
411 uint8_t vdev_id;
412 struct pmo_vdev_priv_obj *vdev_ctx;
413
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700414 pmo_enter();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530415 if (!vdev) {
416 pmo_err("vdev is NULL");
417 status = QDF_STATUS_E_INVAL;
418 goto out;
419 }
420
421 status = pmo_vdev_get_ref(vdev);
422 if (status != QDF_STATUS_SUCCESS)
423 goto out;
424
425 vdev_ctx = pmo_vdev_get_priv(vdev);
426
427 status = pmo_core_ns_offload_sanity(vdev);
428 if (status != QDF_STATUS_SUCCESS)
429 goto dec_ref;
430
431 if (trigger == pmo_ns_offload_dynamic_update) {
432 /*
433 * user disable ns offload using ioctl/vendor cmd dynamically.
434 */
435 vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic =
436 false;
437 goto skip_ns_dynamic_check;
438 }
439
440 if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) {
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700441 pmo_debug("ns offload dynamically disable");
Mukul Sharmad75a6672017-06-22 15:40:53 +0530442 status = QDF_STATUS_E_INVAL;
443 goto dec_ref;
444 }
445
446skip_ns_dynamic_check:
447 vdev_id = pmo_vdev_get_id(vdev);
Rajeev Kumar08f67ca2017-09-25 17:06:51 -0700448 pmo_debug("disable ns offload in fwr vdev id: %d vdev: %pK trigger: %d",
Mukul Sharmad75a6672017-06-22 15:40:53 +0530449 vdev_id, vdev, trigger);
450
451 status = pmo_core_do_disable_ns_offload(vdev, vdev_id, trigger);
452dec_ref:
453 pmo_vdev_put_ref(vdev);
454out:
Dustin Brownb2cd2e02018-03-15 11:59:45 -0700455 pmo_exit();
Mukul Sharmad75a6672017-06-22 15:40:53 +0530456
457 return status;
458}
459
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530460QDF_STATUS
461pmo_core_get_ns_offload_params(struct wlan_objmgr_vdev *vdev,
462 struct pmo_ns_offload_params *params)
463{
464 QDF_STATUS status;
465 struct pmo_vdev_priv_obj *vdev_ctx;
466
467 pmo_enter();
468
469 if (!params)
470 return QDF_STATUS_E_INVAL;
471
472 qdf_mem_zero(params, sizeof(*params));
473
474 if (!vdev) {
475 pmo_err("vdev is NULL");
476 status = QDF_STATUS_E_INVAL;
477 goto out;
478 }
479
480 status = pmo_vdev_get_ref(vdev);
481 if (status != QDF_STATUS_SUCCESS)
482 goto out;
483
484 vdev_ctx = pmo_vdev_get_priv(vdev);
485
486 status = pmo_core_ns_offload_sanity(vdev);
487 if (status != QDF_STATUS_SUCCESS)
488 goto dec_ref;
489
490 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock);
491 *params = vdev_ctx->vdev_ns_req;
492 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock);
493
494dec_ref:
495 pmo_vdev_put_ref(vdev);
496out:
497 pmo_exit();
498
499 return status;
500}