blob: f51c02e5a9aa38782c281007766c54f642ee52ce [file] [log] [blame]
Sandeep Puligilla00d2a1f2017-12-21 00:21:44 -08001/*
Sandeep Puligilla019a1bd2018-02-04 22:57:44 -08002 * Copyright (c) 2017, 2018 The Linux Foundation. All rights reserved.
Sandeep Puligilla00d2a1f2017-12-21 00:21:44 -08003 *
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: wlan_hdd_spectral_scan.c
21 *
22 * WLAN Host Device Driver Spectral Scan Implementation
23 */
24
25#include <linux/version.h>
26#include <linux/module.h>
27#include <linux/kernel.h>
28#include <net/cfg80211.h>
29#include "wlan_hdd_includes.h"
30#include "cds_api.h"
31#include "ani_global.h"
32#include "wlan_cfg80211_spectral.h"
33#include "wlan_hdd_spectralscan.h"
Sandeep Puligilla019a1bd2018-02-04 22:57:44 -080034#include <wlan_spectral_ucfg_api.h>
35#ifdef CNSS_GENL
36#include <net/cnss_nl.h>
37#endif
Sandeep Puligilla00d2a1f2017-12-21 00:21:44 -080038
39/**
40 * __wlan_hdd_cfg80211_spectral_scan_start() - start spectral scan
41 * @wiphy: WIPHY structure pointer
42 * @wdev: Wireless device structure pointer
43 * @data: Pointer to the data received
44 * @data_len: Length of the data received
45 *
46 * This function starts spectral scan
47 *
48 * Return: 0 on success and errno on failure
49 */
50static int __wlan_hdd_cfg80211_spectral_scan_start(struct wiphy *wiphy,
51 struct wireless_dev *wdev,
52 const void *data,
53 int data_len)
54{
55 int ret;
56 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
57
58 ENTER();
59
60 ret = wlan_hdd_validate_context(hdd_ctx);
61 if (ret)
62 return ret;
63
64 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
65 hdd_err("Command not allowed in FTM mode");
66 return -EPERM;
67 }
68
69 ret = wlan_cfg80211_spectral_scan_config_and_start(wiphy,
70 hdd_ctx->hdd_pdev,
71 data, data_len);
72 EXIT();
73
74 return ret;
75}
76
77/**
78 * __wlan_hdd_cfg80211_spectral_scan_stop() - stop spectral scan
79 * @wiphy: WIPHY structure pointer
80 * @wdev: Wireless device structure pointer
81 * @data: Pointer to the data received
82 * @data_len: Length of the data received
83 *
84 * This function stops spectral scan
85 *
86 * Return: 0 on success and errno on failure
87 */
88static int __wlan_hdd_cfg80211_spectral_scan_stop(struct wiphy *wiphy,
89 struct wireless_dev *wdev,
90 const void *data,
91 int data_len)
92{
93 int ret;
94 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
95
96 ENTER();
97
98 ret = wlan_hdd_validate_context(hdd_ctx);
99 if (ret)
100 return ret;
101
102 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
103 hdd_err("Command not allowed in FTM mode");
104 return -EPERM;
105 }
106
107 ret = wlan_cfg80211_spectral_scan_stop(wiphy, hdd_ctx->hdd_pdev,
108 data, data_len);
109 EXIT();
110
111 return ret;
112}
113
114/**
115 * __wlan_hdd_cfg80211_spectral_scan_get_config() - spectral scan get config
116 * @wiphy: WIPHY structure pointer
117 * @wdev: Wireless device structure pointer
118 * @data: Pointer to the data received
119 * @data_len: Length of the data received
120 *
121 * This function to get the spectral scan configuration
122 *
123 * Return: 0 on success and errno on failure
124 */
125static int __wlan_hdd_cfg80211_spectral_scan_get_config(
126 struct wiphy *wiphy,
127 struct wireless_dev *wdev,
128 const void *data,
129 int data_len)
130{
131 int ret;
132 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
133
134 ENTER();
135
136 ret = wlan_hdd_validate_context(hdd_ctx);
137 if (ret)
138 return ret;
139
140 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
141 hdd_err("Command not allowed in FTM mode");
142 return -EPERM;
143 }
144
145 ret = wlan_cfg80211_spectral_scan_get_config(wiphy, hdd_ctx->hdd_pdev,
146 data, data_len);
147 EXIT();
148
149 return ret;
150}
151
152/**
153 * __wlan_hdd_cfg80211_spectral_scan_get_diag_stats() - get diag stats
154 * @wiphy: WIPHY structure pointer
155 * @wdev: Wireless device structure pointer
156 * @data: Pointer to the data received
157 * @data_len: Length of the data received
158 *
159 * This function gets the spectral scan diag stats
160 *
161 * Return: 0 on success and errno on failure
162 */
163static int __wlan_hdd_cfg80211_spectral_scan_get_diag_stats(
164 struct wiphy *wiphy,
165 struct wireless_dev *wdev,
166 const void *data,
167 int data_len)
168{
169 int ret;
170 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
171
172 ENTER();
173
174 ret = wlan_hdd_validate_context(hdd_ctx);
175 if (ret)
176 return ret;
177
178 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
179 hdd_err("Command not allowed in FTM mode");
180 return -EPERM;
181 }
182
183 ret = wlan_cfg80211_spectral_scan_get_diag_stats(wiphy,
184 hdd_ctx->hdd_pdev,
185 data, data_len);
186 EXIT();
187
188 return ret;
189}
190
191/**
192 * __wlan_hdd_cfg80211_spectral_scan_get_cap_info() - get spectral caps
193 * @wiphy: WIPHY structure pointer
194 * @wdev: Wireless device structure pointer
195 * @data: Pointer to the data received
196 * @data_len: Length of the data received
197 *
198 * This function gets spectral scan configured capabilities
199 *
200 * Return: 0 on success and errno on failure
201 */
202static int __wlan_hdd_cfg80211_spectral_scan_get_cap_info(
203 struct wiphy *wiphy,
204 struct wireless_dev *wdev,
205 const void *data,
206 int data_len)
207{
208 int ret;
209 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
210
211 ENTER();
212
213 ret = wlan_hdd_validate_context(hdd_ctx);
214 if (ret)
215 return ret;
216
217 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
218 hdd_err("Command not allowed in FTM mode");
219 return -EPERM;
220 }
221
222 ret = wlan_cfg80211_spectral_scan_get_cap(wiphy, hdd_ctx->hdd_pdev,
223 data, data_len);
224 EXIT();
225
226 return ret;
227}
228
229/*
230 * __wlan_hdd_cfg80211_spectral_scan_get_status() - get spectral scan
231 * status
232 * @wiphy: WIPHY structure pointer
233 * @wdev: Wireless device structure pointer
234 * @data: Pointer to the data received
235 * @data_len: Length of the data received
236 *
237 * This function gets current status of spectral scan
238 *
239 * Return: 0 on success and errno on failure
240 */
241static int __wlan_hdd_cfg80211_spectral_scan_get_status(
242 struct wiphy *wiphy,
243 struct wireless_dev *wdev,
244 const void *data,
245 int data_len)
246{
247 int ret;
248 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
249
250 ENTER();
251
252 ret = wlan_hdd_validate_context(hdd_ctx);
253 if (ret)
254 return ret;
255
256 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
257 hdd_err("Command not allowed in FTM mode");
258 return -EPERM;
259 }
260
261 ret = wlan_cfg80211_spectral_scan_get_status(wiphy, hdd_ctx->hdd_pdev,
262 data, data_len);
263 EXIT();
264
265 return ret;
266}
267
268int wlan_hdd_cfg80211_spectral_scan_start(struct wiphy *wiphy,
269 struct wireless_dev *wdev,
270 const void *data,
271 int data_len)
272{
273 int ret;
274
275 cds_ssr_protect(__func__);
276 ret = __wlan_hdd_cfg80211_spectral_scan_start(
277 wiphy, wdev, data, data_len);
278 cds_ssr_unprotect(__func__);
279
280 return ret;
281}
282
283int wlan_hdd_cfg80211_spectral_scan_stop(struct wiphy *wiphy,
284 struct wireless_dev *wdev,
285 const void *data,
286 int data_len)
287{
288 int ret;
289
290 cds_ssr_protect(__func__);
291 ret = __wlan_hdd_cfg80211_spectral_scan_stop(
292 wiphy, wdev, data, data_len);
293
294 cds_ssr_unprotect(__func__);
295
296 return ret;
297}
298
299int wlan_hdd_cfg80211_spectral_scam_get_config(struct wiphy *wiphy,
300 struct wireless_dev *wdev,
301 const void *data,
302 int data_len)
303{
304 int ret;
305
306 cds_ssr_protect(__func__);
307 ret = __wlan_hdd_cfg80211_spectral_scan_get_config(
308 wiphy, wdev, data, data_len);
309
310 cds_ssr_unprotect(__func__);
311
312 return ret;
313}
314
315int wlan_hdd_cfg80211_spectral_scan_get_diag_stats(struct wiphy *wiphy,
316 struct wireless_dev *wdev,
317 const void *data,
318 int data_len)
319{
320 int ret;
321
322 cds_ssr_protect(__func__);
323 ret = __wlan_hdd_cfg80211_spectral_scan_get_diag_stats(
324 wiphy, wdev, data, data_len);
325
326 cds_ssr_unprotect(__func__);
327
328 return ret;
329}
330
331int wlan_hdd_cfg80211_spectral_scan_get_cap_info(struct wiphy *wiphy,
332 struct wireless_dev *wdev,
333 const void *data,
334 int data_len)
335{
336 int ret;
337
338 cds_ssr_protect(__func__);
339 ret = __wlan_hdd_cfg80211_spectral_scan_get_cap_info(
340 wiphy, wdev, data, data_len);
341 cds_ssr_unprotect(__func__);
342
343 return ret;
344}
345
346int wlan_hdd_cfg80211_spectral_scan_get_status(struct wiphy *wiphy,
347 struct wireless_dev *wdev,
348 const void *data,
349 int data_len)
350{
351 int ret;
352
353 cds_ssr_protect(__func__);
354 ret = __wlan_hdd_cfg80211_spectral_scan_get_status(
355 wiphy, wdev, data, data_len);
356
357 cds_ssr_unprotect(__func__);
358
359 return ret;
360}
Sandeep Puligilla019a1bd2018-02-04 22:57:44 -0800361
362#ifdef CNSS_GENL
363static void send_spectral_scan_reg_rsp_msg(struct hdd_context *hdd_ctx)
364{
365 struct sk_buff *skb;
366 struct nlmsghdr *nlh;
367 struct spectral_scan_msg *rsp_msg;
368 int err;
369
370 skb = alloc_skb(NLMSG_SPACE(sizeof(struct spectral_scan_msg)),
371 GFP_KERNEL);
372 if (skb == NULL) {
373 hdd_err("Skb allocation failed");
374 return;
375 }
376
377 nlh = (struct nlmsghdr *)skb->data;
378 nlh->nlmsg_pid = 0;
379 nlh->nlmsg_flags = 0;
380 nlh->nlmsg_seq = 0;
381 nlh->nlmsg_type = WLAN_NL_MSG_SPECTRAL_SCAN;
382
383 rsp_msg = NLMSG_DATA(nlh);
384 rsp_msg->msg_type = SPECTRAL_SCAN_REGISTER_RSP;
385 rsp_msg->pid = hdd_ctx->sscan_pid;
386
387 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct spectral_scan_msg));
388 skb_put(skb, NLMSG_SPACE(sizeof(struct spectral_scan_msg)));
389
390 hdd_info("sending App Reg Response to process pid %d",
391 hdd_ctx->sscan_pid);
392
393 err = nl_srv_ucast(skb, hdd_ctx->sscan_pid, MSG_DONTWAIT,
394 WLAN_NL_MSG_SPECTRAL_SCAN, CLD80211_MCGRP_OEM_MSGS);
395
396 if (err < 0)
397 hdd_err("SPECTRAL: failed to send to spectral scan reg"
398 " response");
399}
400
401/**
402 * __spectral_scan_msg_handler() - API to handle spectral scan
403 * command
404 * @data: Data received
405 * @data_len: length of the data received
406 * @ctx: Pointer to stored context
407 * @pid: Process ID
408 *
409 * API to handle spectral scan commands from user space
410 *
411 * Return: None
412 */
413static void __spectral_scan_msg_handler(const void *data, int data_len,
414 void *ctx, int pid)
415{
416 struct spectral_scan_msg *ss_msg = NULL;
417 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1];
418 struct hdd_context *hdd_ctx;
419 int ret;
420
421 hdd_ctx = (struct hdd_context *)cds_get_context(QDF_MODULE_ID_HDD);
422 ret = wlan_hdd_validate_context(hdd_ctx);
423 if (0 != ret)
424 return;
425
426 if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data,
427 data_len, NULL)) {
428 hdd_err("nla parse fails");
429 return;
430 }
431
432 if (!tb[CLD80211_ATTR_DATA]) {
433 hdd_err("attr VENDOR_DATA fails");
434 return;
435 }
436 ss_msg = (struct spectral_scan_msg *)nla_data(tb[CLD80211_ATTR_DATA]);
437
438 if (!ss_msg) {
439 hdd_err("data NULL");
440 return;
441 }
442
443 switch (ss_msg->msg_type) {
444 case SPECTRAL_SCAN_REGISTER_REQ:
445 hdd_ctx->sscan_pid = ss_msg->pid;
446 hdd_debug("spectral scan application registered, pid=%d",
447 hdd_ctx->sscan_pid);
448 send_spectral_scan_reg_rsp_msg(hdd_ctx);
449 ucfg_spectral_scan_set_ppid(hdd_ctx->hdd_pdev,
450 hdd_ctx->sscan_pid);
451 break;
452 default:
453 hdd_warn("invalid message type %d", ss_msg->msg_type);
454 break;
455 }
456}
457
458static void spectral_scan_msg_handler(const void *data, int data_len,
459 void *ctx, int pid)
460{
461 cds_ssr_protect(__func__);
462 __spectral_scan_msg_handler(data, data_len, ctx, pid);
463 cds_ssr_unprotect(__func__);
464}
465
466/**
467 * spectral_scan_activate_service() - API to register spectral
468 * scan cmd handler
469 *
470 * API to register the spectral scan command handler using new
471 * genl infra. Return type is zero to match with legacy
472 * prototype
473 *
474 * Return: 0
475 */
476int spectral_scan_activate_service(void)
477{
478 register_cld_cmd_cb(WLAN_NL_MSG_SPECTRAL_SCAN,
479 spectral_scan_msg_handler, NULL);
480 return 0;
481}
Sandeep Puligillaad399cd2018-02-12 11:32:29 -0800482#else
483int spectral_scan_activate_service(void)
484{
485 return 0;
486}
Sandeep Puligilla019a1bd2018-02-04 22:57:44 -0800487#endif