blob: 4e71c475903621d10f575b8cad8011e005808403 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Dustin Brown4ea21db2018-01-05 14:13:17 -08002 * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ocb.c
30 *
31 * WLAN Host Device Driver 802.11p OCB implementation
32 */
33
34#include "cds_sched.h"
35#include "wlan_hdd_assoc.h"
36#include "wlan_hdd_main.h"
37#include "wlan_hdd_ocb.h"
38#include "wlan_hdd_trace.h"
Jeff Johnson7af334b2017-02-01 13:03:43 -080039#include "wlan_hdd_request_manager.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040#include "wlan_tgt_def_config.h"
41#include "sch_api.h"
42#include "wma_api.h"
Leo Changfdb45c32016-10-28 11:09:23 -070043#include <cdp_txrx_cmn.h>
Manjunathappa Prakash3454fd62016-04-01 08:52:06 -070044#include <cdp_txrx_peer_ops.h>
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -080045#include <cdp_txrx_handle.h>
Zhang Qian47e22ce2018-01-04 15:38:38 +080046#include "wlan_ocb_public_structs.h"
47#include "wlan_ocb_ucfg_api.h"
48#include <cdp_txrx_cmn.h>
49#include <cdp_txrx_peer_ops.h>
50#include <cdp_txrx_handle.h>
51#include <cdp_txrx_ocb.h>
52
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053/* Structure definitions for WLAN_SET_DOT11P_CHANNEL_SCHED */
54#define AIFSN_MIN (2)
55#define AIFSN_MAX (15)
56#define CW_MIN (1)
57#define CW_MAX (10)
58
59/* Maximum time(ms) to wait for OCB operations */
60#define WLAN_WAIT_TIME_OCB_CMD 1500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080061
62/**
63 * hdd_set_dot11p_config() - Set 802.11p config flag
64 * @hdd_ctx: HDD Context pointer
65 *
66 * TODO-OCB: This has been temporarily added to ensure this paramter
67 * is set in CSR when we init the channel list. This should be removed
68 * once the 5.9 GHz channels are added to the regulatory domain.
69 */
Jeff Johnson7106aba2017-08-28 11:49:07 -070070void hdd_set_dot11p_config(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080071{
72 sme_set_dot11p_config(hdd_ctx->hHal,
73 hdd_ctx->config->dot11p_mode !=
74 WLAN_HDD_11P_DISABLED);
75}
76
77/**
78 * dot11p_validate_qos_params() - Check if QoS parameters are valid
79 * @qos_params: Array of QoS parameters
80 *
81 * Return: 0 on success. error code on failure.
82 */
Zhang Qian47e22ce2018-01-04 15:38:38 +080083static int dot11p_validate_qos_params(struct ocb_wmm_param qos_params[])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080084{
85 int i;
86
87 for (i = 0; i < MAX_NUM_AC; i++) {
88 if ((!qos_params[i].aifsn) && (!qos_params[i].cwmin)
89 && (!qos_params[i].cwmax))
90 continue;
91
92 /* Validate AIFSN */
93 if ((qos_params[i].aifsn < AIFSN_MIN)
94 || (qos_params[i].aifsn > AIFSN_MAX)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -070095 hdd_err("Invalid QoS parameter aifsn %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080096 qos_params[i].aifsn);
97 return -EINVAL;
98 }
99
100 /* Validate CWMin */
101 if ((qos_params[i].cwmin < CW_MIN)
102 || (qos_params[i].cwmin > CW_MAX)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700103 hdd_err("Invalid QoS parameter cwmin %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800104 qos_params[i].cwmin);
105 return -EINVAL;
106 }
107
108 /* Validate CWMax */
109 if ((qos_params[i].cwmax < CW_MIN)
110 || (qos_params[i].cwmax > CW_MAX)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700111 hdd_err("Invalid QoS parameter cwmax %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800112 qos_params[i].cwmax);
113 return -EINVAL;
114 }
115 }
116
117 return 0;
118}
119
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800120/**
121 * dot11p_validate_channel() - validates a DSRC channel
122 * @center_freq: the channel's center frequency
123 * @bandwidth: the channel's bandwidth
124 * @tx_power: transmit power
125 * @reg_power: (output) the max tx power from the regulatory domain
126 * @antenna_max: (output) the max antenna gain from the regulatory domain
127 *
128 * Return: 0 if the channel is valid, error code otherwise.
129 */
130static int dot11p_validate_channel(struct wiphy *wiphy,
131 uint32_t channel_freq, uint32_t bandwidth,
132 uint32_t tx_power, uint8_t *reg_power,
133 uint8_t *antenna_max)
134{
135 int band_idx, channel_idx;
136 struct ieee80211_supported_band *current_band;
137 struct ieee80211_channel *current_channel;
138
Srinivas Girigowda5da651b2017-08-04 11:22:54 -0700139 for (band_idx = 0; band_idx < HDD_NUM_NL80211_BANDS; band_idx++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 current_band = wiphy->bands[band_idx];
141 if (!current_band)
142 continue;
143
144 for (channel_idx = 0; channel_idx < current_band->n_channels;
145 channel_idx++) {
146 current_channel = &current_band->channels[channel_idx];
147
148 if (channel_freq == current_channel->center_freq) {
149 if (current_channel->flags &
150 IEEE80211_CHAN_DISABLED)
151 return -EINVAL;
152
153 if (reg_power)
154 *reg_power =
155 current_channel->max_reg_power;
156 if (antenna_max)
157 *antenna_max =
158 current_channel->
159 max_antenna_gain;
160
161 switch (bandwidth) {
162 case 0:
163 if (current_channel->flags &
164 IEEE80211_CHAN_NO_10MHZ)
165 bandwidth = 5;
166 else if (current_channel->flags &
167 IEEE80211_CHAN_NO_20MHZ)
168 bandwidth = 10;
169 else
170 bandwidth = 20;
171 break;
172 case 5:
173 break;
174 case 10:
175 if (current_channel->flags &
176 IEEE80211_CHAN_NO_10MHZ)
177 return -EINVAL;
178 break;
179 case 20:
180 if (current_channel->flags &
181 IEEE80211_CHAN_NO_20MHZ)
182 return -EINVAL;
183 break;
184 default:
185 return -EINVAL;
186 }
187
188 if (tx_power > current_channel->max_power)
189 return -EINVAL;
190
191 return 0;
192 }
193 }
194 }
195
Amar Singhalfda6eda2015-11-02 15:08:59 -0800196 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800197}
198
199/**
200 * hdd_ocb_validate_config() - Validates the config data
201 * @config: configuration to be validated
202 *
203 * Return: 0 on success.
204 */
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700205static int hdd_ocb_validate_config(struct hdd_adapter *adapter,
Zhang Qian47e22ce2018-01-04 15:38:38 +0800206 struct ocb_config *config)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800207{
208 int i;
Jeff Johnson7106aba2017-08-28 11:49:07 -0700209 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800210
211 for (i = 0; i < config->channel_count; i++) {
212 if (dot11p_validate_channel(hdd_ctx->wiphy,
213 config->channels[i].chan_freq,
214 config->channels[i].bandwidth,
215 config->channels[i].max_pwr,
216 &config->channels[i].reg_pwr,
217 &config->channels[i].antenna_max)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700218 hdd_err("Invalid channel frequency %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800219 config->channels[i].chan_freq);
220 return -EINVAL;
221 }
222 if (dot11p_validate_qos_params(config->channels[i].qos_params))
223 return -EINVAL;
224 }
225
226 return 0;
227}
228
229/**
230 * hdd_ocb_register_sta() - Register station with Transport Layer
231 * @adapter: Pointer to HDD Adapter
232 *
233 * This function should be invoked in the OCB Set Schedule callback
234 * to enable the data path in the TL by calling RegisterSTAClient
235 *
236 * Return: 0 on success. -1 on failure.
237 */
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700238static int hdd_ocb_register_sta(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800239{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530240 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800241 struct ol_txrx_desc_type sta_desc = {0};
Jeff Johnson7106aba2017-08-28 11:49:07 -0700242 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond377dce2017-10-04 10:32:42 -0700243 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800244 uint8_t peer_id;
Dhanashri Atre182b0272016-02-17 15:35:07 -0800245 struct ol_txrx_ops txrx_ops;
Leo Changfdb45c32016-10-28 11:09:23 -0700246 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
247 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800248
Jeff Johnson382bce02017-09-01 14:21:07 -0700249 qdf_status = cdp_peer_register_ocb_peer(soc,
Jeff Johnson1e851a12017-10-28 14:36:12 -0700250 adapter->mac_addr.bytes,
Leo Changfdb45c32016-10-28 11:09:23 -0700251 &peer_id);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530252 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700253 hdd_err("Error registering OCB Self Peer!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800254 return -EINVAL;
255 }
256
257 hdd_ctx->sta_to_adapter[peer_id] = adapter;
258
259 sta_desc.sta_id = peer_id;
260 sta_desc.is_qos_enabled = 1;
261
Dhanashri Atre182b0272016-02-17 15:35:07 -0800262 /* Register the vdev transmit and receive functions */
263 qdf_mem_zero(&txrx_ops, sizeof(txrx_ops));
264 txrx_ops.rx.rx = hdd_rx_packet_cbk;
Leo Changfdb45c32016-10-28 11:09:23 -0700265 cdp_vdev_register(soc,
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -0800266 (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700267 (struct cdp_pdev *)pdev, adapter->session_id),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -0800268 adapter, &txrx_ops);
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800269 adapter->tx_fn = txrx_ops.tx.tx;
Dhanashri Atre182b0272016-02-17 15:35:07 -0800270
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -0800271 qdf_status = cdp_peer_register(soc,
272 (struct cdp_pdev *)pdev, &sta_desc);
Dhanashri Atre50141c52016-04-07 13:15:29 -0700273 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700274 hdd_err("Failed to register. Status= %d [0x%08X]",
Dhanashri Atre50141c52016-04-07 13:15:29 -0700275 qdf_status, qdf_status);
276 return -EINVAL;
277 }
278
Jeff Johnsond377dce2017-10-04 10:32:42 -0700279 if (sta_ctx->conn_info.staId[0] != HDD_WLAN_INVALID_STA_ID &&
280 sta_ctx->conn_info.staId[0] != peer_id) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700281 hdd_err("The ID for the OCB station has changed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800282 }
283
Jeff Johnsond377dce2017-10-04 10:32:42 -0700284 sta_ctx->conn_info.staId[0] = peer_id;
285 qdf_copy_macaddr(&sta_ctx->conn_info.peerMacAddress[0],
Jeff Johnson1e851a12017-10-28 14:36:12 -0700286 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800287
288 return 0;
289}
290
291/**
292 * hdd_ocb_config_new() - Creates a new OCB configuration
293 * @num_channels: the number of channels
294 * @num_schedule: the schedule size
295 * @ndl_chan_list_len: length in bytes of the NDL chan blob
296 * @ndl_active_state_list_len: length in bytes of the active state blob
297 *
298 * Return: A pointer to the OCB configuration struct, NULL on failure.
299 */
Jeff Johnson929ad032016-10-19 07:34:42 -0700300static
Zhang Qian47e22ce2018-01-04 15:38:38 +0800301struct ocb_config *hdd_ocb_config_new(uint32_t num_channels,
302 uint32_t num_schedule,
303 uint32_t ndl_chan_list_len,
304 uint32_t ndl_active_state_list_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800305{
Zhang Qian47e22ce2018-01-04 15:38:38 +0800306 struct ocb_config *ret = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800307 uint32_t len;
308 void *cursor;
309
310 if (num_channels > CFG_TGT_NUM_OCB_CHANNELS ||
311 num_schedule > CFG_TGT_NUM_OCB_SCHEDULES)
312 return NULL;
313
314 len = sizeof(*ret) +
Zhang Qian47e22ce2018-01-04 15:38:38 +0800315 num_channels * sizeof(struct ocb_config_chan) +
316 num_schedule * sizeof(struct ocb_config_schdl) +
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800317 ndl_chan_list_len +
318 ndl_active_state_list_len;
319
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530320 cursor = qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800321 if (!cursor)
322 goto fail;
323
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800324 ret = cursor;
325 cursor += sizeof(*ret);
326
327 ret->channel_count = num_channels;
328 ret->channels = cursor;
329 cursor += num_channels * sizeof(*ret->channels);
330
331 ret->schedule_size = num_schedule;
332 ret->schedule = cursor;
333 cursor += num_schedule * sizeof(*ret->schedule);
334
335 ret->dcc_ndl_chan_list = cursor;
336 cursor += ndl_chan_list_len;
337
338 ret->dcc_ndl_active_state_list = cursor;
339 cursor += ndl_active_state_list_len;
340
341 return ret;
342
343fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530344 qdf_mem_free(ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800345 return NULL;
346}
347
Jeff Johnson7af334b2017-02-01 13:03:43 -0800348struct hdd_ocb_set_config_priv {
349 int status;
350};
351
352
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800353/**
354 * hdd_ocb_set_config_callback() - OCB set config callback function
355 * @context_ptr: OCB call context
356 * @response_ptr: Pointer to response structure
357 *
358 * This function is registered as a callback with the lower layers
359 * and is used to respond with the status of a OCB set config command.
360 */
361static void hdd_ocb_set_config_callback(void *context_ptr, void *response_ptr)
362{
Jeff Johnson7af334b2017-02-01 13:03:43 -0800363 struct hdd_request *hdd_request;
364 struct hdd_ocb_set_config_priv *priv;
Zhang Qian47e22ce2018-01-04 15:38:38 +0800365 struct ocb_set_config_response *response = response_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800366
Jeff Johnson7af334b2017-02-01 13:03:43 -0800367 hdd_request = hdd_request_get(context_ptr);
368 if (!hdd_request) {
369 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800371 }
Jeff Johnson7af334b2017-02-01 13:03:43 -0800372 priv = hdd_request_priv(hdd_request);
373
374 if (response && response->status)
Srinivas Girigowdaaaea4102017-03-25 11:02:52 -0700375 hdd_warn("Operation failed: %d", response->status);
Jeff Johnson7af334b2017-02-01 13:03:43 -0800376
Zhang Qian47e22ce2018-01-04 15:38:38 +0800377 if (response && (response->status == OCB_CHANNEL_CONFIG_SUCCESS))
Jeff Johnson7af334b2017-02-01 13:03:43 -0800378 priv->status = 0;
379 else
380 priv->status = -EINVAL;
381
382 hdd_request_complete(hdd_request);
383 hdd_request_put(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800384}
385
386/**
387 * hdd_ocb_set_config_req() - Send an OCB set config request
388 * @adapter: a pointer to the adapter
389 * @config: a pointer to the OCB configuration
390 *
391 * Return: 0 on success.
392 */
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700393static int hdd_ocb_set_config_req(struct hdd_adapter *adapter,
Zhang Qian47e22ce2018-01-04 15:38:38 +0800394 struct ocb_config *config)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800395{
396 int rc;
Jeff Johnson7af334b2017-02-01 13:03:43 -0800397 QDF_STATUS status;
Jeff Johnson7af334b2017-02-01 13:03:43 -0800398 void *cookie;
399 struct hdd_request *hdd_request;
400 struct hdd_ocb_set_config_priv *priv;
401 static const struct hdd_request_params params = {
402 .priv_size = sizeof(*priv),
403 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
404 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800405
406 if (hdd_ocb_validate_config(adapter, config)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700407 hdd_err("The configuration is invalid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800408 return -EINVAL;
409 }
410
Jeff Johnson7af334b2017-02-01 13:03:43 -0800411 hdd_request = hdd_request_alloc(&params);
412 if (!hdd_request) {
413 hdd_err("Request allocation failure");
414 return -ENOMEM;
415 }
416 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800417
Varun Reddy Yeturu8a5d3d42017-08-02 13:03:27 -0700418 hdd_debug("Disabling queues");
Himanshu Agarwal865201d2017-04-12 15:45:31 +0530419 wlan_hdd_netif_queue_control(adapter,
420 WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
421 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800422
Zhang Qian47e22ce2018-01-04 15:38:38 +0800423 status = ucfg_ocb_set_channel_config(adapter->hdd_vdev, config,
424 hdd_ocb_set_config_callback,
425 cookie);
Jeff Johnson7af334b2017-02-01 13:03:43 -0800426 if (QDF_IS_STATUS_ERROR(status)) {
Zhang Qian47e22ce2018-01-04 15:38:38 +0800427 hdd_err("Failed to set channel config.");
Jeff Johnson7af334b2017-02-01 13:03:43 -0800428 rc = qdf_status_to_os_return(status);
429 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800430 }
431
432 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -0800433 rc = hdd_request_wait_for_response(hdd_request);
434 if (rc) {
435 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800436 goto end;
437 }
438
Jeff Johnson7af334b2017-02-01 13:03:43 -0800439 priv = hdd_request_priv(hdd_request);
440 rc = priv->status;
441 if (rc) {
442 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800443 goto end;
444 }
445
Jeff Johnson7af334b2017-02-01 13:03:43 -0800446 /*
447 * OCB set config command successful.
448 * Open the TX data path
449 */
450 if (!hdd_ocb_register_sta(adapter))
451 wlan_hdd_netif_queue_control(adapter,
452 WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
453 WLAN_CONTROL_PATH);
454
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800455 /* fall through */
456end:
Jeff Johnson7af334b2017-02-01 13:03:43 -0800457 hdd_request_put(hdd_request);
458
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800459 return rc;
460}
461
462/**
463 * __iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED
464 * ioctl
465 * @dev: Pointer to net_device structure
466 * @iw_request_info: IW Request Info
467 * @wrqu: IW Request Userspace Data Pointer
468 * @extra: IW Request Kernel Data Pointer
469 *
470 * Return: 0 on success
471 */
472static int __iw_set_dot11p_channel_sched(struct net_device *dev,
473 struct iw_request_info *info,
474 union iwreq_data *wrqu, char *extra)
475{
Jeff Johnson441e1f72017-02-07 08:50:49 -0800476 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477 struct dot11p_channel_sched *sched;
Jeff Johnson7106aba2017-08-28 11:49:07 -0700478 struct hdd_context *hdd_ctx;
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700479 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Zhang Qian47e22ce2018-01-04 15:38:38 +0800480 struct ocb_config *config = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800481 uint8_t *mac_addr;
482 int i, j;
Zhang Qian47e22ce2018-01-04 15:38:38 +0800483 struct ocb_config_chan *curr_chan;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800484
Jeff Johnson6ee91ee2016-02-11 18:55:30 -0800485 ENTER_DEV(dev);
486
Jeff Johnson382bce02017-09-01 14:21:07 -0700487 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson441e1f72017-02-07 08:50:49 -0800488 rc = wlan_hdd_validate_context(hdd_ctx);
489 if (0 != rc)
490 return rc;
491
492 rc = hdd_check_private_wext_control(hdd_ctx, info);
493 if (0 != rc)
494 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800495
Krunal Sonibe766b02016-03-10 13:00:44 -0800496 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700497 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800498 return -EINVAL;
499 }
500
501 sched = (struct dot11p_channel_sched *)extra;
502
503 /* Scheduled slots same as num channels for compatibility */
504 config = hdd_ocb_config_new(sched->num_channels, sched->num_channels,
505 0, 0);
506 if (config == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700507 hdd_err("Failed to allocate memory!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800508 return -ENOMEM;
509 }
510
511 /* Identify the vdev interface */
Zhang Qian47e22ce2018-01-04 15:38:38 +0800512 config->vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800513
514 /* Release all the mac addresses used for OCB */
515 for (i = 0; i < adapter->ocb_mac_addr_count; i++) {
Jeff Johnson399c6272017-08-30 10:51:00 -0700516 wlan_hdd_release_intf_addr(hdd_ctx,
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800517 adapter->ocb_mac_address[i].bytes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800518 }
519 adapter->ocb_mac_addr_count = 0;
520
521 config->channel_count = 0;
522 for (i = 0; i < sched->num_channels; i++) {
523 if (0 == sched->channels[i].channel_freq)
524 continue;
525
526 curr_chan = &(config->channels[config->channel_count]);
527
528 curr_chan->chan_freq = sched->channels[i].channel_freq;
529 /*
530 * tx_power is divided by 2 because ocb_channel.tx_power is
Zhang Qian47e22ce2018-01-04 15:38:38 +0800531 * in half dB increments and ocb_config_channel.max_pwr
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800532 * is in 1 dB increments.
533 */
534 curr_chan->max_pwr = sched->channels[i].tx_power / 2;
535 curr_chan->bandwidth = sched->channels[i].channel_bandwidth;
536 /* assume 10 as default if not provided */
537 if (curr_chan->bandwidth == 0)
538 curr_chan->bandwidth = 10;
539
540 /*
541 * Setup locally administered mac addresses for each channel.
542 * First channel uses the adapter's address.
543 */
544 if (i == 0) {
Anurag Chouhanc5548422016-02-24 18:33:27 +0530545 qdf_copy_macaddr(&curr_chan->mac_address,
Jeff Johnson1e851a12017-10-28 14:36:12 -0700546 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800547 } else {
Jeff Johnson399c6272017-08-30 10:51:00 -0700548 mac_addr = wlan_hdd_get_intf_addr(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800549 if (mac_addr == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700550 hdd_err("Cannot obtain mac address");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800551 rc = -EINVAL;
552 goto fail;
553 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530554 qdf_mem_copy(config->channels[
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800555 config->channel_count].mac_address.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800556 mac_addr, sizeof(tSirMacAddr));
557 /* Save the mac address to release later */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530558 qdf_mem_copy(adapter->ocb_mac_address[
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800559 adapter->ocb_mac_addr_count].bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530560 mac_addr, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800561 adapter->ocb_mac_addr_count++;
562 }
563
564 for (j = 0; j < MAX_NUM_AC; j++) {
565 curr_chan->qos_params[j].aifsn =
566 sched->channels[i].qos_params[j].aifsn;
567 curr_chan->qos_params[j].cwmin =
568 sched->channels[i].qos_params[j].cwmin;
569 curr_chan->qos_params[j].cwmax =
570 sched->channels[i].qos_params[j].cwmax;
571 }
572
573 config->channel_count++;
574 }
575
576 /*
577 * Scheduled slots same as num channels for compatibility with
578 * legacy use.
579 */
580 for (i = 0; i < sched->num_channels; i++) {
581 config->schedule[i].chan_freq = sched->channels[i].channel_freq;
582 config->schedule[i].guard_interval =
583 sched->channels[i].start_guard_interval;
584 config->schedule[i].total_duration =
585 sched->channels[i].duration;
586 }
587
588 rc = hdd_ocb_set_config_req(adapter, config);
589 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700590 hdd_err("Error while setting OCB config");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800591 goto fail;
592 }
593
594 rc = 0;
595
596fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530597 qdf_mem_free(config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800598 return rc;
599}
600
601/**
602 * iw_set_dot11p_channel_sched() - IOCTL interface for setting channel schedule
603 * @dev: Pointer to net_device structure
604 * @iw_request_info: IW Request Info
605 * @wrqu: IW Request Userspace Data Pointer
606 * @extra: IW Request Kernel Data Pointer
607 *
608 * Return: 0 on success.
609 */
610int iw_set_dot11p_channel_sched(struct net_device *dev,
611 struct iw_request_info *info,
612 union iwreq_data *wrqu, char *extra)
613{
614 int ret;
615
616 cds_ssr_protect(__func__);
617 ret = __iw_set_dot11p_channel_sched(dev, info, wrqu, extra);
618 cds_ssr_unprotect(__func__);
619
620 return ret;
621}
622
623static const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[
624 QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1] = {
625 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT] = {
626 .type = NLA_U32
627 },
628 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE] = {
629 .type = NLA_U32
630 },
631 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY] = {
632 .type = NLA_BINARY
633 },
634 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY] = {
635 .type = NLA_BINARY
636 },
637 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY] = {
638 .type = NLA_BINARY
639 },
640 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY] = {
641 .type = NLA_BINARY
642 },
643 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS] = {
644 .type = NLA_U32
645 },
646};
647
648static const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[
649 QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1] = {
650 [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE] = {
651 .type = NLA_BINARY, .len = SIZE_UTC_TIME
652 },
653 [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR] = {
654 .type = NLA_BINARY, .len = SIZE_UTC_TIME_ERROR
655 },
656};
657
658static const struct nla_policy qca_wlan_vendor_ocb_start_timing_advert_policy[
659 QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1] = {
660 [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ] = {
661 .type = NLA_U32
662 },
663 [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE] = {
664 .type = NLA_U32
665 },
666};
667
668static const struct nla_policy qca_wlan_vendor_ocb_stop_timing_advert_policy[
669 QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1] = {
670 [QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ] = {
671 .type = NLA_U32
672 },
673};
674
675static const struct nla_policy qca_wlan_vendor_ocb_get_tsf_timer_resp[] = {
676 [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH] = {
677 .type = NLA_U32
678 },
679 [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW] = {
680 .type = NLA_U32
681 },
682};
683
684static const struct nla_policy qca_wlan_vendor_dcc_get_stats[] = {
685 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] = {
686 .type = NLA_U32
687 },
688 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY] = {
689 .type = NLA_BINARY
690 },
691};
692
693static const struct nla_policy qca_wlan_vendor_dcc_get_stats_resp[] = {
694 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT] = {
695 .type = NLA_U32
696 },
697 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY] = {
698 .type = NLA_BINARY
699 },
700};
701
702static const struct nla_policy qca_wlan_vendor_dcc_clear_stats[] = {
703 [QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP] = {
704 .type = NLA_U32
705 },
706};
707
708static const struct nla_policy qca_wlan_vendor_dcc_update_ndl[
709 QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1] = {
710 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] = {
711 .type = NLA_U32
712 },
713 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] = {
714 .type = NLA_BINARY
715 },
716 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY] = {
717 .type = NLA_BINARY
718 },
719};
720
721/**
722 * struct wlan_hdd_ocb_config_channel
723 * @chan_freq: frequency of the channel
724 * @bandwidth: bandwidth of the channel, either 10 or 20 MHz
725 * @mac_address: MAC address assigned to this channel
726 * @qos_params: QoS parameters
727 * @max_pwr: maximum transmit power of the channel (1/2 dBm)
728 * @min_pwr: minimum transmit power of the channel (1/2 dBm)
729 */
730struct wlan_hdd_ocb_config_channel {
731 uint32_t chan_freq;
732 uint32_t bandwidth;
733 uint16_t flags;
734 uint8_t reserved[4];
735 struct sir_qos_params qos_params[MAX_NUM_AC];
736 uint32_t max_pwr;
737 uint32_t min_pwr;
738};
739
Zhang Qian47e22ce2018-01-04 15:38:38 +0800740static void wlan_hdd_ocb_config_channel_to_ocb_config_channel(
741 struct ocb_config_chan *dest,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742 struct wlan_hdd_ocb_config_channel *src,
743 uint32_t channel_count)
744{
745 uint32_t i;
746
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530747 qdf_mem_zero(dest, channel_count * sizeof(*dest));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800748
749 for (i = 0; i < channel_count; i++) {
750 dest[i].chan_freq = src[i].chan_freq;
751 dest[i].bandwidth = src[i].bandwidth;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530752 qdf_mem_copy(dest[i].qos_params, src[i].qos_params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800753 sizeof(dest[i].qos_params));
754 /*
755 * max_pwr and min_pwr are divided by 2 because
Zhang Qian47e22ce2018-01-04 15:38:38 +0800756 * ocb_channel_param.max_pwr and min_pwr
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800757 * are in 1/2 dB increments and
Zhang Qian47e22ce2018-01-04 15:38:38 +0800758 * ocb_config_channel.max_pwr and min_pwr are in
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800759 * 1 dB increments.
760 */
761 dest[i].max_pwr = src[i].max_pwr / 2;
762 dest[i].min_pwr = (src[i].min_pwr + 1) / 2;
763 dest[i].flags = src[i].flags;
764 }
765}
766
767/**
768 * __wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command
769 * @wiphy: pointer to the wiphy
770 * @wdev: pointer to the wdev
771 * @data: The netlink data
772 * @data_len: The length of the netlink data in bytes
773 *
774 * Return: 0 on success.
775 */
776static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy,
777 struct wireless_dev *wdev,
778 const void *data,
779 int data_len)
780{
Jeff Johnson7106aba2017-08-28 11:49:07 -0700781 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800782 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700783 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800784 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1];
785 struct nlattr *channel_array;
786 struct nlattr *sched_array;
787 struct nlattr *ndl_chan_list;
788 uint32_t ndl_chan_list_len;
789 struct nlattr *ndl_active_state_list;
790 uint32_t ndl_active_state_list_len;
791 uint32_t flags = 0;
792 int i;
Jeff Johnson929ad032016-10-19 07:34:42 -0700793 uint32_t channel_count, schedule_size;
Zhang Qian47e22ce2018-01-04 15:38:38 +0800794 struct ocb_config *config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800795 int rc = -EINVAL;
796 uint8_t *mac_addr;
797
Jeff Johnson1f61b612016-02-12 16:28:33 -0800798 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530800 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800801 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800802
Krunal Sonibe766b02016-03-10 13:00:44 -0800803 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700804 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800805 return -EINVAL;
806 }
807
808 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -0800809 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX,
810 data, data_len,
811 qca_wlan_vendor_ocb_set_config_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700812 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813 return -EINVAL;
814 }
815
816 /* Get the number of channels in the schedule */
817 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700818 hdd_err("CHANNEL_COUNT is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800819 return -EINVAL;
820 }
821 channel_count = nla_get_u32(
822 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]);
823
824 /* Get the size of the channel schedule */
825 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700826 hdd_err("SCHEDULE_SIZE is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800827 return -EINVAL;
828 }
829 schedule_size = nla_get_u32(
830 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]);
831
832 /* Get the ndl chan array and the ndl active state array. */
SaidiReddy Yenuga3db38772017-03-28 15:18:56 +0530833 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY]) {
834 hdd_err("NDL_CHANNEL_ARRAY is not present");
835 return -EINVAL;
836 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800837 ndl_chan_list =
838 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY];
839 ndl_chan_list_len = (ndl_chan_list ? nla_len(ndl_chan_list) : 0);
840
SaidiReddy Yenuga3db38772017-03-28 15:18:56 +0530841 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY]) {
842 hdd_err("NDL_ACTIVE_STATE_ARRAY is not present");
843 return -EINVAL;
844 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800845 ndl_active_state_list =
846 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY];
847 ndl_active_state_list_len = (ndl_active_state_list ?
848 nla_len(ndl_active_state_list) : 0);
849
850 /* Get the flags */
851 if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS])
852 flags = nla_get_u32(tb[
853 QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]);
854
855 config = hdd_ocb_config_new(channel_count, schedule_size,
856 ndl_chan_list_len,
857 ndl_active_state_list_len);
858 if (config == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700859 hdd_err("Failed to allocate memory!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800860 return -ENOMEM;
861 }
862
863 config->channel_count = channel_count;
864 config->schedule_size = schedule_size;
865 config->flags = flags;
866
867 /* Read the channel array */
868 channel_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY];
869 if (!channel_array) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700870 hdd_err("No channel present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800871 goto fail;
872 }
873 if (nla_len(channel_array) != channel_count *
874 sizeof(struct wlan_hdd_ocb_config_channel)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700875 hdd_err("CHANNEL_ARRAY is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800876 goto fail;
877 }
Zhang Qian47e22ce2018-01-04 15:38:38 +0800878 wlan_hdd_ocb_config_channel_to_ocb_config_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800879 config->channels, nla_data(channel_array), channel_count);
880
881 /* Identify the vdev interface */
Zhang Qian47e22ce2018-01-04 15:38:38 +0800882 config->vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800883
884 /* Release all the mac addresses used for OCB */
885 for (i = 0; i < adapter->ocb_mac_addr_count; i++) {
Jeff Johnson399c6272017-08-30 10:51:00 -0700886 wlan_hdd_release_intf_addr(hdd_ctx,
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800887 adapter->ocb_mac_address[i].bytes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 }
889 adapter->ocb_mac_addr_count = 0;
890
891 /*
892 * Setup locally administered mac addresses for each channel.
893 * First channel uses the adapter's address.
894 */
895 for (i = 0; i < config->channel_count; i++) {
896 if (i == 0) {
Anurag Chouhanc5548422016-02-24 18:33:27 +0530897 qdf_copy_macaddr(&config->channels[i].mac_address,
Jeff Johnson1e851a12017-10-28 14:36:12 -0700898 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800899 } else {
Jeff Johnson399c6272017-08-30 10:51:00 -0700900 mac_addr = wlan_hdd_get_intf_addr(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800901 if (mac_addr == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700902 hdd_err("Cannot obtain mac address");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800903 goto fail;
904 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530905 qdf_mem_copy(config->channels[i].mac_address.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530906 mac_addr, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800907 /* Save the mac address to release later */
Anurag Chouhanc5548422016-02-24 18:33:27 +0530908 qdf_copy_macaddr(&adapter->ocb_mac_address[
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800909 adapter->ocb_mac_addr_count],
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800910 &config->channels[i].mac_address);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800911 adapter->ocb_mac_addr_count++;
912 }
913 }
914
915 /* Read the schedule array */
916 sched_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY];
917 if (!sched_array) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700918 hdd_err("No channel present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800919 goto fail;
920 }
921 if (nla_len(sched_array) != schedule_size * sizeof(*config->schedule)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700922 hdd_err("SCHEDULE_ARRAY is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800923 goto fail;
924 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530925 qdf_mem_copy(config->schedule, nla_data(sched_array),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800926 nla_len(sched_array));
927
928 /* Copy the NDL chan array */
929 if (ndl_chan_list_len) {
930 config->dcc_ndl_chan_list_len = ndl_chan_list_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530931 qdf_mem_copy(config->dcc_ndl_chan_list, nla_data(ndl_chan_list),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932 nla_len(ndl_chan_list));
933 }
934
935 /* Copy the NDL active state array */
936 if (ndl_active_state_list_len) {
937 config->dcc_ndl_active_state_list_len =
938 ndl_active_state_list_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530939 qdf_mem_copy(config->dcc_ndl_active_state_list,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800940 nla_data(ndl_active_state_list),
941 nla_len(ndl_active_state_list));
942 }
943
944 rc = hdd_ocb_set_config_req(adapter, config);
945 if (rc)
Jeff Johnson5f735d52016-07-06 15:14:45 -0700946 hdd_err("Error while setting OCB config: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800947
948fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530949 qdf_mem_free(config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800950 return rc;
951}
952
953/**
954 * wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command
955 * @wiphy: pointer to the wiphy
956 * @wdev: pointer to the wdev
957 * @data: The netlink data
958 * @data_len: The length of the netlink data in bytes
959 *
960 * Return: 0 on success.
961 */
962int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy,
963 struct wireless_dev *wdev,
964 const void *data,
965 int data_len)
966{
967 int ret;
968
969 cds_ssr_protect(__func__);
970 ret = __wlan_hdd_cfg80211_ocb_set_config(wiphy, wdev, data, data_len);
971 cds_ssr_unprotect(__func__);
972
973 return ret;
974}
975
976/**
977 * __wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for set UTC time command
978 * @wiphy: pointer to the wiphy
979 * @wdev: pointer to the wdev
980 * @data: The netlink data
981 * @data_len: The length of the netlink data in bytes
982 *
983 * Return: 0 on success.
984 */
985static int __wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy,
986 struct wireless_dev *wdev,
987 const void *data,
988 int data_len)
989{
Jeff Johnson7106aba2017-08-28 11:49:07 -0700990 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800991 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700992 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800993 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1];
994 struct nlattr *utc_attr;
995 struct nlattr *time_error_attr;
Zhang Qian47e22ce2018-01-04 15:38:38 +0800996 struct ocb_utc_param *utc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800997 int rc = -EINVAL;
998
Jeff Johnson1f61b612016-02-12 16:28:33 -0800999 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001000
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301001 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001002 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001003
Krunal Sonibe766b02016-03-10 13:00:44 -08001004 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001005 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006 return -EINVAL;
1007 }
1008
Jeff Johnson1b780e42017-10-31 14:11:45 -07001009 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001010 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011 return -EINVAL;
1012 }
1013
1014 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001015 if (wlan_cfg80211_nla_parse(tb,
1016 QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX,
1017 data, data_len,
1018 qca_wlan_vendor_ocb_set_utc_time_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001019 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001020 return -EINVAL;
1021 }
1022
1023 /* Read the UTC time */
1024 utc_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE];
1025 if (!utc_attr) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001026 hdd_err("UTC_TIME is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001027 return -EINVAL;
1028 }
1029 if (nla_len(utc_attr) != SIZE_UTC_TIME) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001030 hdd_err("UTC_TIME is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001031 return -EINVAL;
1032 }
1033
1034 /* Read the time error */
1035 time_error_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR];
1036 if (!time_error_attr) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001037 hdd_err("UTC_TIME is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001038 return -EINVAL;
1039 }
1040 if (nla_len(time_error_attr) != SIZE_UTC_TIME_ERROR) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001041 hdd_err("UTC_TIME is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 return -EINVAL;
1043 }
1044
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301045 utc = qdf_mem_malloc(sizeof(*utc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 if (!utc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001047 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001048 return -ENOMEM;
1049 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07001050 utc->vdev_id = adapter->session_id;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301051 qdf_mem_copy(utc->utc_time, nla_data(utc_attr), SIZE_UTC_TIME);
1052 qdf_mem_copy(utc->time_error, nla_data(time_error_attr),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001053 SIZE_UTC_TIME_ERROR);
1054
Zhang Qian47e22ce2018-01-04 15:38:38 +08001055 if (ucfg_ocb_set_utc_time(adapter->hdd_vdev, utc) !=
1056 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001057 hdd_err("Error while setting UTC time");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001058 rc = -EINVAL;
1059 } else {
1060 rc = 0;
1061 }
1062
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301063 qdf_mem_free(utc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001064 return rc;
1065}
1066
1067/**
1068 * wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for the set UTC time command
1069 * @wiphy: pointer to the wiphy
1070 * @wdev: pointer to the wdev
1071 * @data: The netlink data
1072 * @data_len: The length of the netlink data in bytes
1073 *
1074 * Return: 0 on success.
1075 */
1076int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy,
1077 struct wireless_dev *wdev,
1078 const void *data,
1079 int data_len)
1080{
1081 int ret;
1082
1083 cds_ssr_protect(__func__);
1084 ret = __wlan_hdd_cfg80211_ocb_set_utc_time(wiphy, wdev, data, data_len);
1085 cds_ssr_unprotect(__func__);
1086
1087 return ret;
1088}
1089
1090/**
1091 * __wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for start TA cmd
1092 * @wiphy: pointer to the wiphy
1093 * @wdev: pointer to the wdev
1094 * @data: The netlink data
1095 * @data_len: The length of the netlink data in bytes
1096 *
1097 * Return: 0 on success.
1098 */
1099static int
1100__wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy,
1101 struct wireless_dev *wdev,
1102 const void *data,
1103 int data_len)
1104{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001105 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001107 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1];
Zhang Qian47e22ce2018-01-04 15:38:38 +08001109 struct ocb_timing_advert_param *timing_advert;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001110 int rc = -EINVAL;
1111
Jeff Johnson1f61b612016-02-12 16:28:33 -08001112 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001113
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301114 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001115 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001116
Krunal Sonibe766b02016-03-10 13:00:44 -08001117 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001118 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001119 return -EINVAL;
1120 }
1121
Jeff Johnson1b780e42017-10-31 14:11:45 -07001122 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001123 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001124 return -EINVAL;
1125 }
1126
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301127 timing_advert = qdf_mem_malloc(sizeof(*timing_advert));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 if (!timing_advert) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001129 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001130 return -ENOMEM;
1131 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07001132 timing_advert->vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133
1134 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001135 if (wlan_cfg80211_nla_parse(tb,
1136 QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX,
1137 data, data_len,
1138 qca_wlan_vendor_ocb_start_timing_advert_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001139 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001140 goto fail;
1141 }
1142
1143 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001144 hdd_err("CHANNEL_FREQ is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 goto fail;
1146 }
1147 timing_advert->chan_freq = nla_get_u32(
1148 tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]);
1149
1150 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001151 hdd_err("REPEAT_RATE is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001152 goto fail;
1153 }
1154 timing_advert->repeat_rate = nla_get_u32(
1155 tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]);
1156
1157 timing_advert->template_length =
Naveen Rawatb4d37622015-11-13 16:15:25 -08001158 sme_ocb_gen_timing_advert_frame(hdd_ctx->hHal,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001159 *(tSirMacAddr *)&adapter->mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001160 &timing_advert->template_value,
1161 &timing_advert->timestamp_offset,
1162 &timing_advert->time_value_offset);
1163 if (timing_advert->template_length <= 0) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001164 hdd_err("Error while generating the TA frame");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001165 goto fail;
1166 }
1167
Zhang Qian47e22ce2018-01-04 15:38:38 +08001168 if (ucfg_ocb_start_timing_advert(adapter->hdd_vdev, timing_advert) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301169 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001170 hdd_err("Error while starting timing advert");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001171 rc = -EINVAL;
1172 } else {
1173 rc = 0;
1174 }
1175
1176fail:
1177 if (timing_advert->template_value)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301178 qdf_mem_free(timing_advert->template_value);
1179 qdf_mem_free(timing_advert);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001180 return rc;
1181}
1182
1183/**
1184 * wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for the start TA cmd
1185 * @wiphy: pointer to the wiphy
1186 * @wdev: pointer to the wdev
1187 * @data: The netlink data
1188 * @data_len: The length of the netlink data in bytes
1189 *
1190 * Return: 0 on success.
1191 */
1192int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy,
1193 struct wireless_dev *wdev,
1194 const void *data,
1195 int data_len)
1196{
1197 int ret;
1198
1199 cds_ssr_protect(__func__);
1200 ret = __wlan_hdd_cfg80211_ocb_start_timing_advert(wiphy, wdev,
1201 data, data_len);
1202 cds_ssr_unprotect(__func__);
1203
1204 return ret;
1205}
1206
1207/**
1208 * __wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd
1209 * @wiphy: pointer to the wiphy
1210 * @wdev: pointer to the wdev
1211 * @data: The netlink data
1212 * @data_len: The length of the netlink data in bytes
1213 *
1214 * Return: 0 on success.
1215 */
1216static int
1217__wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy,
1218 struct wireless_dev *wdev,
1219 const void *data,
1220 int data_len)
1221{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001222 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001223 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001224 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001225 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1];
Zhang Qian47e22ce2018-01-04 15:38:38 +08001226 struct ocb_timing_advert_param *timing_advert;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001227 int rc = -EINVAL;
1228
Jeff Johnson1f61b612016-02-12 16:28:33 -08001229 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301231 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001233
Krunal Sonibe766b02016-03-10 13:00:44 -08001234 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001235 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001236 return -EINVAL;
1237 }
1238
Jeff Johnson1b780e42017-10-31 14:11:45 -07001239 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001240 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001241 return -EINVAL;
1242 }
1243
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301244 timing_advert = qdf_mem_malloc(sizeof(*timing_advert));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001245 if (!timing_advert) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001246 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001247 return -ENOMEM;
1248 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07001249 timing_advert->vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250
1251 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001252 if (wlan_cfg80211_nla_parse(tb,
1253 QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX,
1254 data, data_len,
1255 qca_wlan_vendor_ocb_stop_timing_advert_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001256 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001257 goto fail;
1258 }
1259
1260 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001261 hdd_err("CHANNEL_FREQ is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001262 goto fail;
1263 }
1264 timing_advert->chan_freq = nla_get_u32(
1265 tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]);
1266
Zhang Qian47e22ce2018-01-04 15:38:38 +08001267 if (ucfg_ocb_stop_timing_advert(adapter->hdd_vdev, timing_advert) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301268 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001269 hdd_err("Error while stopping timing advert");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001270 rc = -EINVAL;
1271 } else {
1272 rc = 0;
1273 }
1274
1275fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301276 qdf_mem_free(timing_advert);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001277 return rc;
1278}
1279
1280/**
1281 * wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd
1282 * @wiphy: pointer to the wiphy
1283 * @wdev: pointer to the wdev
1284 * @data: The netlink data
1285 * @data_len: The length of the netlink data in bytes
1286 *
1287 * Return: 0 on success.
1288 */
1289int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy,
1290 struct wireless_dev *wdev,
1291 const void *data,
1292 int data_len)
1293{
1294 int ret;
1295
1296 cds_ssr_protect(__func__);
1297 ret = __wlan_hdd_cfg80211_ocb_stop_timing_advert(wiphy, wdev,
1298 data, data_len);
1299 cds_ssr_unprotect(__func__);
1300
1301 return ret;
1302}
1303
Jeff Johnson7af334b2017-02-01 13:03:43 -08001304struct hdd_ocb_get_tsf_timer_priv {
Zhang Qian47e22ce2018-01-04 15:38:38 +08001305 struct ocb_get_tsf_timer_response response;
Jeff Johnson7af334b2017-02-01 13:03:43 -08001306 int status;
1307};
1308
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001309/**
1310 * hdd_ocb_get_tsf_timer_callback() - Callback to get TSF command
1311 * @context_ptr: request context
1312 * @response_ptr: response data
1313 */
1314static void hdd_ocb_get_tsf_timer_callback(void *context_ptr,
1315 void *response_ptr)
1316{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001317 struct hdd_request *hdd_request;
1318 struct hdd_ocb_get_tsf_timer_priv *priv;
Zhang Qian47e22ce2018-01-04 15:38:38 +08001319 struct ocb_get_tsf_timer_response *response = response_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001320
Jeff Johnson7af334b2017-02-01 13:03:43 -08001321 hdd_request = hdd_request_get(context_ptr);
1322 if (!hdd_request) {
1323 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001324 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001325 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001326
Zhang Qian47e22ce2018-01-04 15:38:38 +08001327 priv = hdd_request_priv(hdd_request);
Jeff Johnson7af334b2017-02-01 13:03:43 -08001328 if (response) {
1329 priv->response = *response;
1330 priv->status = 0;
1331 } else {
1332 priv->status = -EINVAL;
1333 }
1334 hdd_request_complete(hdd_request);
1335 hdd_request_put(hdd_request);
1336}
1337
1338static int
1339hdd_ocb_get_tsf_timer_reply(struct wiphy *wiphy,
Zhang Qian47e22ce2018-01-04 15:38:38 +08001340 struct ocb_get_tsf_timer_response *response)
Jeff Johnson7af334b2017-02-01 13:03:43 -08001341{
1342 uint32_t nl_buf_len;
1343 struct sk_buff *nl_resp;
1344 int rc;
1345
1346 /* Allocate the buffer for the response. */
1347 nl_buf_len = NLMSG_HDRLEN;
1348 nl_buf_len += 2 * (NLA_HDRLEN + sizeof(uint32_t));
1349 nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
1350 if (!nl_resp) {
1351 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
1352 return -ENOMEM;
1353 }
1354
1355 /* Populate the response. */
1356 rc = nla_put_u32(nl_resp,
1357 QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH,
1358 response->timer_high);
1359 if (rc)
1360 goto end;
1361 rc = nla_put_u32(nl_resp,
1362 QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW,
1363 response->timer_low);
1364 if (rc)
1365 goto end;
1366
1367 /* Send the response. */
1368 rc = cfg80211_vendor_cmd_reply(nl_resp);
1369 nl_resp = NULL;
1370 if (rc) {
1371 hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc);
1372 goto end;
1373 }
1374end:
1375 if (nl_resp)
1376 kfree_skb(nl_resp);
1377
1378 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001379}
1380
1381/**
1382 * __wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd
1383 * @wiphy: pointer to the wiphy
1384 * @wdev: pointer to the wdev
1385 * @data: The netlink data
1386 * @data_len: The length of the netlink data in bytes
1387 *
1388 * Return: 0 on success.
1389 */
1390static int
1391__wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy,
1392 struct wireless_dev *wdev,
1393 const void *data,
1394 int data_len)
1395{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001396 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001397 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001398 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson7af334b2017-02-01 13:03:43 -08001399 int rc;
Zhang Qian47e22ce2018-01-04 15:38:38 +08001400 struct ocb_get_tsf_timer_param request = {0};
Jeff Johnson7af334b2017-02-01 13:03:43 -08001401 QDF_STATUS status;
1402 void *cookie;
1403 struct hdd_request *hdd_request;
1404 struct hdd_ocb_get_tsf_timer_priv *priv;
1405 static const struct hdd_request_params params = {
1406 .priv_size = sizeof(*priv),
1407 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1408 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001409
Jeff Johnson1f61b612016-02-12 16:28:33 -08001410 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001411
Jeff Johnson7af334b2017-02-01 13:03:43 -08001412 rc = wlan_hdd_validate_context(hdd_ctx);
1413 if (rc)
1414 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415
Krunal Sonibe766b02016-03-10 13:00:44 -08001416 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001417 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001418 return -EINVAL;
1419 }
1420
Jeff Johnson1b780e42017-10-31 14:11:45 -07001421 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001422 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001423 return -EINVAL;
1424 }
1425
Jeff Johnson7af334b2017-02-01 13:03:43 -08001426 hdd_request = hdd_request_alloc(&params);
1427 if (!hdd_request) {
1428 hdd_err("Request allocation failure");
1429 return -ENOMEM;
1430 }
1431 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001432
Jeff Johnson1b780e42017-10-31 14:11:45 -07001433 request.vdev_id = adapter->session_id;
Zhang Qian47e22ce2018-01-04 15:38:38 +08001434 status = ucfg_ocb_get_tsf_timer(adapter->hdd_vdev, &request,
1435 hdd_ocb_get_tsf_timer_callback,
1436 cookie);
Jeff Johnson7af334b2017-02-01 13:03:43 -08001437 if (QDF_IS_STATUS_ERROR(status)) {
Zhang Qian47e22ce2018-01-04 15:38:38 +08001438 hdd_err("Failed to get tsf timer.");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001439 rc = qdf_status_to_os_return(status);
1440 goto end;
1441 }
1442
1443 rc = hdd_request_wait_for_response(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001444 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001445 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446 goto end;
1447 }
1448
Jeff Johnson7af334b2017-02-01 13:03:43 -08001449 priv = hdd_request_priv(hdd_request);
1450 rc = priv->status;
1451 if (rc) {
1452 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001453 goto end;
1454 }
1455
Varun Reddy Yeturu8a5d3d42017-08-02 13:03:27 -07001456 hdd_debug("Got TSF timer response, high=%d, low=%d",
Jeff Johnson7af334b2017-02-01 13:03:43 -08001457 priv->response.timer_high,
1458 priv->response.timer_low);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001459
1460 /* Send the response. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001461 rc = hdd_ocb_get_tsf_timer_reply(wiphy, &priv->response);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001462 if (rc) {
Jeff Johnson7af334b2017-02-01 13:03:43 -08001463 hdd_err("hdd_ocb_get_tsf_timer_reply failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 goto end;
1465 }
1466
Jeff Johnson7af334b2017-02-01 13:03:43 -08001467 /* fall through */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001468end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001469 hdd_request_put(hdd_request);
1470
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001471 return rc;
1472}
1473
1474/**
1475 * wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd
1476 * @wiphy: pointer to the wiphy
1477 * @wdev: pointer to the wdev
1478 * @data: The netlink data
1479 * @data_len: The length of the netlink data in bytes
1480 *
1481 * Return: 0 on success.
1482 */
1483int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy,
1484 struct wireless_dev *wdev,
1485 const void *data,
1486 int data_len)
1487{
1488 int ret;
1489
1490 cds_ssr_protect(__func__);
1491 ret = __wlan_hdd_cfg80211_ocb_get_tsf_timer(wiphy, wdev,
1492 data, data_len);
1493 cds_ssr_unprotect(__func__);
1494
1495 return ret;
1496}
1497
Jeff Johnson7af334b2017-02-01 13:03:43 -08001498struct hdd_dcc_stats_priv {
Zhang Qian47e22ce2018-01-04 15:38:38 +08001499 struct ocb_dcc_get_stats_response *response;
Jeff Johnson7af334b2017-02-01 13:03:43 -08001500 int status;
1501};
1502
1503static void hdd_dcc_get_stats_dealloc(void *context_ptr)
1504{
1505 struct hdd_dcc_stats_priv *priv = context_ptr;
1506
1507 qdf_mem_free(priv->response);
1508 priv->response = NULL;
1509}
1510
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001511/**
1512 * hdd_dcc_get_stats_callback() - Callback to get stats command
1513 * @context_ptr: request context
1514 * @response_ptr: response data
1515 */
1516static void hdd_dcc_get_stats_callback(void *context_ptr, void *response_ptr)
1517{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001518 struct hdd_request *hdd_request;
1519 struct hdd_dcc_stats_priv *priv;
Zhang Qian47e22ce2018-01-04 15:38:38 +08001520 struct ocb_dcc_get_stats_response *response = response_ptr;
1521 struct ocb_dcc_get_stats_response *hdd_resp;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001522
Jeff Johnson7af334b2017-02-01 13:03:43 -08001523 hdd_request = hdd_request_get(context_ptr);
1524 if (!hdd_request) {
1525 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001526 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001527 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001528
1529 priv = hdd_request_priv(hdd_request);
1530 if (!response) {
1531 priv->status = -EINVAL;
1532 goto end;
1533 }
1534
1535 priv->response = qdf_mem_malloc(sizeof(*response) +
1536 response->channel_stats_array_len);
1537 if (!priv->response) {
1538 priv->status = -ENOMEM;
1539 goto end;
1540 }
1541
1542 hdd_resp = priv->response;
1543 *hdd_resp = *response;
1544 hdd_resp->channel_stats_array = (void *)hdd_resp + sizeof(*hdd_resp);
1545 qdf_mem_copy(hdd_resp->channel_stats_array,
1546 response->channel_stats_array,
1547 response->channel_stats_array_len);
1548 priv->status = 0;
1549
1550end:
1551 hdd_request_complete(hdd_request);
1552 hdd_request_put(hdd_request);
1553}
1554
1555static int
1556hdd_dcc_get_stats_send_reply(struct wiphy *wiphy,
Zhang Qian47e22ce2018-01-04 15:38:38 +08001557 struct ocb_dcc_get_stats_response *response)
Jeff Johnson7af334b2017-02-01 13:03:43 -08001558{
1559 uint32_t nl_buf_len;
1560 struct sk_buff *nl_resp;
1561 int rc;
1562
1563 /* Allocate the buffer for the response. */
1564 nl_buf_len = NLMSG_HDRLEN;
1565 nl_buf_len += NLA_HDRLEN + sizeof(uint32_t);
1566 nl_buf_len += NLA_HDRLEN + response->channel_stats_array_len;
1567 nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
1568 if (!nl_resp) {
1569 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
1570 return -ENOMEM;
1571 }
1572
1573 /* Populate the response. */
1574 rc = nla_put_u32(nl_resp,
1575 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT,
1576 response->num_channels);
1577 if (rc)
1578 goto end;
1579 rc = nla_put(nl_resp,
1580 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY,
1581 response->channel_stats_array_len,
1582 response->channel_stats_array);
1583 if (rc)
1584 goto end;
1585
1586 /* Send the response. */
1587 rc = cfg80211_vendor_cmd_reply(nl_resp);
1588 nl_resp = NULL;
1589 if (rc) {
1590 hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc);
1591 goto end;
1592 }
1593end:
1594 if (nl_resp)
1595 kfree_skb(nl_resp);
1596
1597 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001598}
1599
1600/**
1601 * __wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats
1602 * @wiphy: pointer to the wiphy
1603 * @wdev: pointer to the wdev
1604 * @data: The netlink data
1605 * @data_len: The length of the netlink data in bytes
1606 *
1607 * Return: 0 on success.
1608 */
1609static int __wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy,
1610 struct wireless_dev *wdev,
1611 const void *data,
1612 int data_len)
1613{
1614 uint32_t channel_count = 0;
1615 uint32_t request_array_len = 0;
1616 void *request_array = 0;
Jeff Johnson7106aba2017-08-28 11:49:07 -07001617 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001618 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001619 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001620 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX + 1];
Jeff Johnson7af334b2017-02-01 13:03:43 -08001621 int rc;
Zhang Qian47e22ce2018-01-04 15:38:38 +08001622 struct ocb_dcc_get_stats_param request = {0};
Jeff Johnson7af334b2017-02-01 13:03:43 -08001623 QDF_STATUS status;
1624 void *cookie;
1625 struct hdd_request *hdd_request;
1626 struct hdd_dcc_stats_priv *priv;
1627 static const struct hdd_request_params params = {
1628 .priv_size = sizeof(*priv),
1629 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1630 .dealloc = hdd_dcc_get_stats_dealloc,
1631 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001632
Jeff Johnson1f61b612016-02-12 16:28:33 -08001633 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634
Jeff Johnson7af334b2017-02-01 13:03:43 -08001635 rc = wlan_hdd_validate_context(hdd_ctx);
1636 if (rc)
1637 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638
Krunal Sonibe766b02016-03-10 13:00:44 -08001639 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001640 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001641 return -EINVAL;
1642 }
1643
Jeff Johnson1b780e42017-10-31 14:11:45 -07001644 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001645 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001646 return -EINVAL;
1647 }
1648
1649 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001650 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX,
1651 data, data_len,
1652 qca_wlan_vendor_dcc_get_stats)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001653 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654 return -EINVAL;
1655 }
1656
1657 /* Validate all the parameters are present */
1658 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] ||
1659 !tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001660 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001661 return -EINVAL;
1662 }
1663
1664 channel_count = nla_get_u32(
1665 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT]);
1666 request_array_len = nla_len(
1667 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]);
1668 request_array = nla_data(
1669 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]);
1670
Jeff Johnson7af334b2017-02-01 13:03:43 -08001671 hdd_request = hdd_request_alloc(&params);
1672 if (!hdd_request) {
1673 hdd_err("Request allocation failure");
1674 return -ENOMEM;
1675 }
1676 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001677
Jeff Johnson1b780e42017-10-31 14:11:45 -07001678 request.vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001679 request.channel_count = channel_count;
1680 request.request_array_len = request_array_len;
1681 request.request_array = request_array;
1682
Zhang Qian47e22ce2018-01-04 15:38:38 +08001683 status = ucfg_ocb_dcc_get_stats(adapter->hdd_vdev, &request,
1684 hdd_dcc_get_stats_callback,
1685 cookie);
Jeff Johnson7af334b2017-02-01 13:03:43 -08001686 if (QDF_IS_STATUS_ERROR(status)) {
Zhang Qian47e22ce2018-01-04 15:38:38 +08001687 hdd_err("Failed to get DCC stats.");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001688 rc = qdf_status_to_os_return(status);
1689 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001690 }
1691
1692 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001693 rc = hdd_request_wait_for_response(hdd_request);
1694 if (rc) {
1695 hdd_err("Operation timed out");
1696 goto end;
1697 }
1698
1699 priv = hdd_request_priv(hdd_request);
1700 rc = priv->status;
1701 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001702 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001703 goto end;
1704 }
1705
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001706 /* Send the response. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001707 rc = hdd_dcc_get_stats_send_reply(wiphy, priv->response);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001708 if (rc) {
Jeff Johnson7af334b2017-02-01 13:03:43 -08001709 hdd_err("hdd_dcc_get_stats_send_reply failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001710 goto end;
1711 }
1712
1713 /* fall through */
1714end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001715 hdd_request_put(hdd_request);
1716
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001717 return rc;
1718}
1719
1720/**
1721 * wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats
1722 * @wiphy: pointer to the wiphy
1723 * @wdev: pointer to the wdev
1724 * @data: The netlink data
1725 * @data_len: The length of the netlink data in bytes
1726 *
1727 * Return: 0 on success.
1728 */
1729int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy,
1730 struct wireless_dev *wdev,
1731 const void *data,
1732 int data_len)
1733{
1734 int ret;
1735
1736 cds_ssr_protect(__func__);
1737 ret = __wlan_hdd_cfg80211_dcc_get_stats(wiphy, wdev,
1738 data, data_len);
1739 cds_ssr_unprotect(__func__);
1740
1741 return ret;
1742}
1743
1744/**
1745 * __wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd
1746 * @wiphy: pointer to the wiphy
1747 * @wdev: pointer to the wdev
1748 * @data: The netlink data
1749 * @data_len: The length of the netlink data in bytes
1750 *
1751 * Return: 0 on success.
1752 */
1753static int __wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy,
1754 struct wireless_dev *wdev,
1755 const void *data,
1756 int data_len)
1757{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001758 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001759 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001760 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX + 1];
1762
Jeff Johnson1f61b612016-02-12 16:28:33 -08001763 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301765 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001766 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001767
Krunal Sonibe766b02016-03-10 13:00:44 -08001768 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001769 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001770 return -EINVAL;
1771 }
1772
Jeff Johnson1b780e42017-10-31 14:11:45 -07001773 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001774 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775 return -EINVAL;
1776 }
1777
1778 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001779 if (wlan_cfg80211_nla_parse(tb,
1780 QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX,
1781 data, data_len,
1782 qca_wlan_vendor_dcc_clear_stats)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001783 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784 return -EINVAL;
1785 }
1786
1787 /* Verify that the parameter is present */
1788 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001789 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001790 return -EINVAL;
1791 }
1792
Zhang Qian47e22ce2018-01-04 15:38:38 +08001793 if (ucfg_ocb_dcc_clear_stats(adapter->hdd_vdev, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001794 nla_get_u32(
1795 tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP])) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301796 QDF_STATUS_SUCCESS) {
Zhang Qian47e22ce2018-01-04 15:38:38 +08001797 hdd_err("Failed to clear DCC stats.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001798 return -EINVAL;
1799 }
1800
1801 return 0;
1802}
1803
1804/**
1805 * wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd
1806 * @wiphy: pointer to the wiphy
1807 * @wdev: pointer to the wdev
1808 * @data: The netlink data
1809 * @data_len: The length of the netlink data in bytes
1810 *
1811 * Return: 0 on success.
1812 */
1813int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy,
1814 struct wireless_dev *wdev,
1815 const void *data,
1816 int data_len)
1817{
1818 int ret;
1819
1820 cds_ssr_protect(__func__);
1821 ret = __wlan_hdd_cfg80211_dcc_clear_stats(wiphy, wdev,
1822 data, data_len);
1823 cds_ssr_unprotect(__func__);
1824
1825 return ret;
1826}
1827
Jeff Johnson7af334b2017-02-01 13:03:43 -08001828struct hdd_dcc_update_ndl_priv {
1829 int status;
1830};
1831
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832/**
1833 * hdd_dcc_update_ndl_callback() - Callback to update NDL command
1834 * @context_ptr: request context
1835 * @response_ptr: response data
1836 */
1837static void hdd_dcc_update_ndl_callback(void *context_ptr, void *response_ptr)
1838{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001839 struct hdd_request *hdd_request;
1840 struct hdd_dcc_update_ndl_priv *priv;
Zhang Qian47e22ce2018-01-04 15:38:38 +08001841 struct ocb_dcc_update_ndl_response *response = response_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001842
Jeff Johnson7af334b2017-02-01 13:03:43 -08001843 hdd_request = hdd_request_get(context_ptr);
1844 if (!hdd_request) {
1845 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001846 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001847 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001848 priv = hdd_request_priv(hdd_request);
1849 if (response && (0 == response->status)) {
1850 priv->status = 0;
1851 } else {
1852 priv->status = -EINVAL;
1853 }
1854 hdd_request_complete(hdd_request);
1855 hdd_request_put(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001856}
1857
1858/**
1859 * __wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd
1860 * @wiphy: pointer to the wiphy
1861 * @wdev: pointer to the wdev
1862 * @data: The netlink data
1863 * @data_len: The length of the netlink data in bytes
1864 *
1865 * Return: 0 on success.
1866 */
1867static int __wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy,
1868 struct wireless_dev *wdev,
1869 const void *data,
1870 int data_len)
1871{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001872 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001873 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001874 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001875 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1];
Zhang Qian47e22ce2018-01-04 15:38:38 +08001876 struct ocb_dcc_update_ndl_param request;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877 uint32_t channel_count;
1878 uint32_t ndl_channel_array_len;
1879 void *ndl_channel_array;
1880 uint32_t ndl_active_state_array_len;
1881 void *ndl_active_state_array;
Jeff Johnson7af334b2017-02-01 13:03:43 -08001882 int rc;
1883 QDF_STATUS status;
1884 void *cookie;
1885 struct hdd_request *hdd_request;
1886 struct hdd_dcc_update_ndl_priv *priv;
1887 static const struct hdd_request_params params = {
1888 .priv_size = sizeof(*priv),
1889 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1890 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891
Jeff Johnson1f61b612016-02-12 16:28:33 -08001892 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001893
Jeff Johnson7af334b2017-02-01 13:03:43 -08001894 rc = wlan_hdd_validate_context(hdd_ctx);
1895 if (rc)
1896 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001897
Krunal Sonibe766b02016-03-10 13:00:44 -08001898 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001899 hdd_err("Device not in OCB mode!");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001900 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001901 }
1902
Jeff Johnson1b780e42017-10-31 14:11:45 -07001903 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001904 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001905 return -EINVAL;
1906 }
1907
1908 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001909 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX,
1910 data, data_len,
1911 qca_wlan_vendor_dcc_update_ndl)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001912 hdd_err("Invalid ATTR");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001913 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001914 }
1915
1916 /* Verify that the parameter is present */
1917 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] ||
1918 !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] ||
1919 !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001920 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001921 return -EINVAL;
1922 }
1923
1924 channel_count = nla_get_u32(
1925 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT]);
1926 ndl_channel_array_len = nla_len(
1927 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]);
1928 ndl_channel_array = nla_data(
1929 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]);
1930 ndl_active_state_array_len = nla_len(
1931 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]);
1932 ndl_active_state_array = nla_data(
1933 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]);
1934
Jeff Johnson7af334b2017-02-01 13:03:43 -08001935 hdd_request = hdd_request_alloc(&params);
1936 if (!hdd_request) {
1937 hdd_err("Request allocation failure");
1938 return -ENOMEM;
1939 }
1940 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001941
1942 /* Copy the parameters to the request structure. */
Jeff Johnson1b780e42017-10-31 14:11:45 -07001943 request.vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001944 request.channel_count = channel_count;
1945 request.dcc_ndl_chan_list_len = ndl_channel_array_len;
1946 request.dcc_ndl_chan_list = ndl_channel_array;
1947 request.dcc_ndl_active_state_list_len = ndl_active_state_array_len;
1948 request.dcc_ndl_active_state_list = ndl_active_state_array;
1949
Zhang Qian47e22ce2018-01-04 15:38:38 +08001950 status = ucfg_ocb_dcc_update_ndl(adapter->hdd_vdev, &request,
1951 hdd_dcc_update_ndl_callback,
1952 cookie);
Jeff Johnson7af334b2017-02-01 13:03:43 -08001953 if (QDF_IS_STATUS_ERROR(status)) {
Zhang Qian47e22ce2018-01-04 15:38:38 +08001954 hdd_err("Failed to update NDL.");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001955 rc = qdf_status_to_os_return(status);
1956 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001957 }
1958
1959 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001960 rc = hdd_request_wait_for_response(hdd_request);
1961 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001962 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001963 goto end;
1964 }
1965
Jeff Johnson7af334b2017-02-01 13:03:43 -08001966 priv = hdd_request_priv(hdd_request);
1967 rc = priv->status;
1968 if (rc) {
1969 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001970 goto end;
1971 }
1972
1973 /* fall through */
1974end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001975 hdd_request_put(hdd_request);
1976
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001977 return rc;
1978}
1979
1980/**
1981 * wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd
1982 * @wiphy: pointer to the wiphy
1983 * @wdev: pointer to the wdev
1984 * @data: The netlink data
1985 * @data_len: The length of the netlink data in bytes
1986 *
1987 * Return: 0 on success.
1988 */
1989int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy,
1990 struct wireless_dev *wdev,
1991 const void *data,
1992 int data_len)
1993{
1994 int ret;
1995
1996 cds_ssr_protect(__func__);
1997 ret = __wlan_hdd_cfg80211_dcc_update_ndl(wiphy, wdev,
1998 data, data_len);
1999 cds_ssr_unprotect(__func__);
2000
2001 return ret;
2002}
2003
2004/**
2005 * wlan_hdd_dcc_stats_event_callback() - Callback to get stats event
2006 * @context_ptr: request context
2007 * @response_ptr: response data
2008 */
2009static void wlan_hdd_dcc_stats_event_callback(void *context_ptr,
2010 void *response_ptr)
2011{
Jeff Johnson7106aba2017-08-28 11:49:07 -07002012 struct hdd_context *hdd_ctx = (struct hdd_context *)context_ptr;
Zhang Qian47e22ce2018-01-04 15:38:38 +08002013 struct ocb_dcc_get_stats_response *resp = response_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002014 struct sk_buff *vendor_event;
2015
2016 ENTER();
2017
2018 vendor_event =
2019 cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2020 NULL, sizeof(uint32_t) + resp->channel_stats_array_len +
2021 NLMSG_HDRLEN,
2022 QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX,
2023 GFP_KERNEL);
2024
2025 if (!vendor_event) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07002026 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002027 return;
2028 }
2029
2030 if (nla_put_u32(vendor_event,
2031 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT,
2032 resp->num_channels) ||
2033 nla_put(vendor_event,
2034 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY,
2035 resp->channel_stats_array_len,
2036 resp->channel_stats_array)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07002037 hdd_err("nla put failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002038 kfree_skb(vendor_event);
2039 return;
2040 }
2041
2042 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2043}
2044
2045/**
2046 * wlan_hdd_dcc_register_for_dcc_stats_event() - Register for dcc stats events
2047 * @hdd_ctx: hdd context
2048 */
Jeff Johnson7106aba2017-08-28 11:49:07 -07002049void wlan_hdd_dcc_register_for_dcc_stats_event(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002050{
2051 int rc;
2052
Zhang Qian47e22ce2018-01-04 15:38:38 +08002053 rc = ucfg_ocb_register_for_dcc_stats_event(hdd_ctx->hdd_pdev, hdd_ctx,
Arun Khandavalli4b55da72016-07-19 19:55:01 +05302054 wlan_hdd_dcc_stats_event_callback);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002055 if (rc)
Zhang Qian47e22ce2018-01-04 15:38:38 +08002056 hdd_err("Register DCC stats callback failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002057}