blob: f11292e7a977463c74617bb168585580fe6d0cd1 [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>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080046/* Structure definitions for WLAN_SET_DOT11P_CHANNEL_SCHED */
47#define AIFSN_MIN (2)
48#define AIFSN_MAX (15)
49#define CW_MIN (1)
50#define CW_MAX (10)
51
52/* Maximum time(ms) to wait for OCB operations */
53#define WLAN_WAIT_TIME_OCB_CMD 1500
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080054
55/**
56 * hdd_set_dot11p_config() - Set 802.11p config flag
57 * @hdd_ctx: HDD Context pointer
58 *
59 * TODO-OCB: This has been temporarily added to ensure this paramter
60 * is set in CSR when we init the channel list. This should be removed
61 * once the 5.9 GHz channels are added to the regulatory domain.
62 */
Jeff Johnson7106aba2017-08-28 11:49:07 -070063void hdd_set_dot11p_config(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080064{
65 sme_set_dot11p_config(hdd_ctx->hHal,
66 hdd_ctx->config->dot11p_mode !=
67 WLAN_HDD_11P_DISABLED);
68}
69
70/**
71 * dot11p_validate_qos_params() - Check if QoS parameters are valid
72 * @qos_params: Array of QoS parameters
73 *
74 * Return: 0 on success. error code on failure.
75 */
76static int dot11p_validate_qos_params(struct sir_qos_params qos_params[])
77{
78 int i;
79
80 for (i = 0; i < MAX_NUM_AC; i++) {
81 if ((!qos_params[i].aifsn) && (!qos_params[i].cwmin)
82 && (!qos_params[i].cwmax))
83 continue;
84
85 /* Validate AIFSN */
86 if ((qos_params[i].aifsn < AIFSN_MIN)
87 || (qos_params[i].aifsn > AIFSN_MAX)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -070088 hdd_err("Invalid QoS parameter aifsn %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080089 qos_params[i].aifsn);
90 return -EINVAL;
91 }
92
93 /* Validate CWMin */
94 if ((qos_params[i].cwmin < CW_MIN)
95 || (qos_params[i].cwmin > CW_MAX)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -070096 hdd_err("Invalid QoS parameter cwmin %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080097 qos_params[i].cwmin);
98 return -EINVAL;
99 }
100
101 /* Validate CWMax */
102 if ((qos_params[i].cwmax < CW_MIN)
103 || (qos_params[i].cwmax > CW_MAX)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700104 hdd_err("Invalid QoS parameter cwmax %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800105 qos_params[i].cwmax);
106 return -EINVAL;
107 }
108 }
109
110 return 0;
111}
112
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800113/**
114 * dot11p_validate_channel() - validates a DSRC channel
115 * @center_freq: the channel's center frequency
116 * @bandwidth: the channel's bandwidth
117 * @tx_power: transmit power
118 * @reg_power: (output) the max tx power from the regulatory domain
119 * @antenna_max: (output) the max antenna gain from the regulatory domain
120 *
121 * Return: 0 if the channel is valid, error code otherwise.
122 */
123static int dot11p_validate_channel(struct wiphy *wiphy,
124 uint32_t channel_freq, uint32_t bandwidth,
125 uint32_t tx_power, uint8_t *reg_power,
126 uint8_t *antenna_max)
127{
128 int band_idx, channel_idx;
129 struct ieee80211_supported_band *current_band;
130 struct ieee80211_channel *current_channel;
131
Srinivas Girigowda5da651b2017-08-04 11:22:54 -0700132 for (band_idx = 0; band_idx < HDD_NUM_NL80211_BANDS; band_idx++) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800133 current_band = wiphy->bands[band_idx];
134 if (!current_band)
135 continue;
136
137 for (channel_idx = 0; channel_idx < current_band->n_channels;
138 channel_idx++) {
139 current_channel = &current_band->channels[channel_idx];
140
141 if (channel_freq == current_channel->center_freq) {
142 if (current_channel->flags &
143 IEEE80211_CHAN_DISABLED)
144 return -EINVAL;
145
146 if (reg_power)
147 *reg_power =
148 current_channel->max_reg_power;
149 if (antenna_max)
150 *antenna_max =
151 current_channel->
152 max_antenna_gain;
153
154 switch (bandwidth) {
155 case 0:
156 if (current_channel->flags &
157 IEEE80211_CHAN_NO_10MHZ)
158 bandwidth = 5;
159 else if (current_channel->flags &
160 IEEE80211_CHAN_NO_20MHZ)
161 bandwidth = 10;
162 else
163 bandwidth = 20;
164 break;
165 case 5:
166 break;
167 case 10:
168 if (current_channel->flags &
169 IEEE80211_CHAN_NO_10MHZ)
170 return -EINVAL;
171 break;
172 case 20:
173 if (current_channel->flags &
174 IEEE80211_CHAN_NO_20MHZ)
175 return -EINVAL;
176 break;
177 default:
178 return -EINVAL;
179 }
180
181 if (tx_power > current_channel->max_power)
182 return -EINVAL;
183
184 return 0;
185 }
186 }
187 }
188
Amar Singhalfda6eda2015-11-02 15:08:59 -0800189 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800190}
191
192/**
193 * hdd_ocb_validate_config() - Validates the config data
194 * @config: configuration to be validated
195 *
196 * Return: 0 on success.
197 */
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700198static int hdd_ocb_validate_config(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800199 struct sir_ocb_config *config)
200{
201 int i;
Jeff Johnson7106aba2017-08-28 11:49:07 -0700202 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203
204 for (i = 0; i < config->channel_count; i++) {
205 if (dot11p_validate_channel(hdd_ctx->wiphy,
206 config->channels[i].chan_freq,
207 config->channels[i].bandwidth,
208 config->channels[i].max_pwr,
209 &config->channels[i].reg_pwr,
210 &config->channels[i].antenna_max)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700211 hdd_err("Invalid channel frequency %d",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800212 config->channels[i].chan_freq);
213 return -EINVAL;
214 }
215 if (dot11p_validate_qos_params(config->channels[i].qos_params))
216 return -EINVAL;
217 }
218
219 return 0;
220}
221
222/**
223 * hdd_ocb_register_sta() - Register station with Transport Layer
224 * @adapter: Pointer to HDD Adapter
225 *
226 * This function should be invoked in the OCB Set Schedule callback
227 * to enable the data path in the TL by calling RegisterSTAClient
228 *
229 * Return: 0 on success. -1 on failure.
230 */
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700231static int hdd_ocb_register_sta(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530233 QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800234 struct ol_txrx_desc_type sta_desc = {0};
Jeff Johnson7106aba2017-08-28 11:49:07 -0700235 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnsond377dce2017-10-04 10:32:42 -0700236 struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800237 uint8_t peer_id;
Dhanashri Atre182b0272016-02-17 15:35:07 -0800238 struct ol_txrx_ops txrx_ops;
Leo Changfdb45c32016-10-28 11:09:23 -0700239 void *soc = cds_get_context(QDF_MODULE_ID_SOC);
240 void *pdev = cds_get_context(QDF_MODULE_ID_TXRX);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800241
Jeff Johnson382bce02017-09-01 14:21:07 -0700242 qdf_status = cdp_peer_register_ocb_peer(soc,
Jeff Johnson1e851a12017-10-28 14:36:12 -0700243 adapter->mac_addr.bytes,
Leo Changfdb45c32016-10-28 11:09:23 -0700244 &peer_id);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530245 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700246 hdd_err("Error registering OCB Self Peer!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800247 return -EINVAL;
248 }
249
250 hdd_ctx->sta_to_adapter[peer_id] = adapter;
251
252 sta_desc.sta_id = peer_id;
253 sta_desc.is_qos_enabled = 1;
254
Dhanashri Atre182b0272016-02-17 15:35:07 -0800255 /* Register the vdev transmit and receive functions */
256 qdf_mem_zero(&txrx_ops, sizeof(txrx_ops));
257 txrx_ops.rx.rx = hdd_rx_packet_cbk;
Leo Changfdb45c32016-10-28 11:09:23 -0700258 cdp_vdev_register(soc,
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -0800259 (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc,
Jeff Johnson1b780e42017-10-31 14:11:45 -0700260 (struct cdp_pdev *)pdev, adapter->session_id),
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -0800261 adapter, &txrx_ops);
Dhanashri Atre168d2b42016-02-22 14:43:06 -0800262 adapter->tx_fn = txrx_ops.tx.tx;
Dhanashri Atre182b0272016-02-17 15:35:07 -0800263
Venkata Sharath Chandra Manchala0d44d452016-11-23 17:48:15 -0800264 qdf_status = cdp_peer_register(soc,
265 (struct cdp_pdev *)pdev, &sta_desc);
Dhanashri Atre50141c52016-04-07 13:15:29 -0700266 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700267 hdd_err("Failed to register. Status= %d [0x%08X]",
Dhanashri Atre50141c52016-04-07 13:15:29 -0700268 qdf_status, qdf_status);
269 return -EINVAL;
270 }
271
Jeff Johnsond377dce2017-10-04 10:32:42 -0700272 if (sta_ctx->conn_info.staId[0] != HDD_WLAN_INVALID_STA_ID &&
273 sta_ctx->conn_info.staId[0] != peer_id) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700274 hdd_err("The ID for the OCB station has changed.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800275 }
276
Jeff Johnsond377dce2017-10-04 10:32:42 -0700277 sta_ctx->conn_info.staId[0] = peer_id;
278 qdf_copy_macaddr(&sta_ctx->conn_info.peerMacAddress[0],
Jeff Johnson1e851a12017-10-28 14:36:12 -0700279 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800280
281 return 0;
282}
283
284/**
285 * hdd_ocb_config_new() - Creates a new OCB configuration
286 * @num_channels: the number of channels
287 * @num_schedule: the schedule size
288 * @ndl_chan_list_len: length in bytes of the NDL chan blob
289 * @ndl_active_state_list_len: length in bytes of the active state blob
290 *
291 * Return: A pointer to the OCB configuration struct, NULL on failure.
292 */
Jeff Johnson929ad032016-10-19 07:34:42 -0700293static
294struct sir_ocb_config *hdd_ocb_config_new(uint32_t num_channels,
295 uint32_t num_schedule,
296 uint32_t ndl_chan_list_len,
297 uint32_t ndl_active_state_list_len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800298{
299 struct sir_ocb_config *ret = 0;
300 uint32_t len;
301 void *cursor;
302
303 if (num_channels > CFG_TGT_NUM_OCB_CHANNELS ||
304 num_schedule > CFG_TGT_NUM_OCB_SCHEDULES)
305 return NULL;
306
307 len = sizeof(*ret) +
308 num_channels * sizeof(struct sir_ocb_config_channel) +
309 num_schedule * sizeof(struct sir_ocb_config_sched) +
310 ndl_chan_list_len +
311 ndl_active_state_list_len;
312
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530313 cursor = qdf_mem_malloc(len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800314 if (!cursor)
315 goto fail;
316
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800317 ret = cursor;
318 cursor += sizeof(*ret);
319
320 ret->channel_count = num_channels;
321 ret->channels = cursor;
322 cursor += num_channels * sizeof(*ret->channels);
323
324 ret->schedule_size = num_schedule;
325 ret->schedule = cursor;
326 cursor += num_schedule * sizeof(*ret->schedule);
327
328 ret->dcc_ndl_chan_list = cursor;
329 cursor += ndl_chan_list_len;
330
331 ret->dcc_ndl_active_state_list = cursor;
332 cursor += ndl_active_state_list_len;
333
334 return ret;
335
336fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530337 qdf_mem_free(ret);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800338 return NULL;
339}
340
Jeff Johnson7af334b2017-02-01 13:03:43 -0800341struct hdd_ocb_set_config_priv {
342 int status;
343};
344
345
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800346/**
347 * hdd_ocb_set_config_callback() - OCB set config callback function
348 * @context_ptr: OCB call context
349 * @response_ptr: Pointer to response structure
350 *
351 * This function is registered as a callback with the lower layers
352 * and is used to respond with the status of a OCB set config command.
353 */
354static void hdd_ocb_set_config_callback(void *context_ptr, void *response_ptr)
355{
Jeff Johnson7af334b2017-02-01 13:03:43 -0800356 struct hdd_request *hdd_request;
357 struct hdd_ocb_set_config_priv *priv;
358 struct sir_ocb_set_config_response *response = response_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800359
Jeff Johnson7af334b2017-02-01 13:03:43 -0800360 hdd_request = hdd_request_get(context_ptr);
361 if (!hdd_request) {
362 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800363 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364 }
Jeff Johnson7af334b2017-02-01 13:03:43 -0800365 priv = hdd_request_priv(hdd_request);
366
367 if (response && response->status)
Srinivas Girigowdaaaea4102017-03-25 11:02:52 -0700368 hdd_warn("Operation failed: %d", response->status);
Jeff Johnson7af334b2017-02-01 13:03:43 -0800369
370 if (response && (0 == response->status))
371 priv->status = 0;
372 else
373 priv->status = -EINVAL;
374
375 hdd_request_complete(hdd_request);
376 hdd_request_put(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800377}
378
379/**
380 * hdd_ocb_set_config_req() - Send an OCB set config request
381 * @adapter: a pointer to the adapter
382 * @config: a pointer to the OCB configuration
383 *
384 * Return: 0 on success.
385 */
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700386static int hdd_ocb_set_config_req(struct hdd_adapter *adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800387 struct sir_ocb_config *config)
388{
389 int rc;
Jeff Johnson7af334b2017-02-01 13:03:43 -0800390 QDF_STATUS status;
Jeff Johnson7106aba2017-08-28 11:49:07 -0700391 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson7af334b2017-02-01 13:03:43 -0800392 void *cookie;
393 struct hdd_request *hdd_request;
394 struct hdd_ocb_set_config_priv *priv;
395 static const struct hdd_request_params params = {
396 .priv_size = sizeof(*priv),
397 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
398 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800399
400 if (hdd_ocb_validate_config(adapter, config)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700401 hdd_err("The configuration is invalid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800402 return -EINVAL;
403 }
404
Jeff Johnson7af334b2017-02-01 13:03:43 -0800405 hdd_request = hdd_request_alloc(&params);
406 if (!hdd_request) {
407 hdd_err("Request allocation failure");
408 return -ENOMEM;
409 }
410 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800411
Varun Reddy Yeturu8a5d3d42017-08-02 13:03:27 -0700412 hdd_debug("Disabling queues");
Himanshu Agarwal865201d2017-04-12 15:45:31 +0530413 wlan_hdd_netif_queue_control(adapter,
414 WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
415 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800416
417 /* Call the SME API to set the config */
Jeff Johnson7af334b2017-02-01 13:03:43 -0800418 status = sme_ocb_set_config(hdd_ctx->hHal, cookie,
419 hdd_ocb_set_config_callback, config);
420 if (QDF_IS_STATUS_ERROR(status)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700421 hdd_err("Error calling SME function.");
Jeff Johnson7af334b2017-02-01 13:03:43 -0800422 rc = qdf_status_to_os_return(status);
423 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800424 }
425
426 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -0800427 rc = hdd_request_wait_for_response(hdd_request);
428 if (rc) {
429 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800430 goto end;
431 }
432
Jeff Johnson7af334b2017-02-01 13:03:43 -0800433 priv = hdd_request_priv(hdd_request);
434 rc = priv->status;
435 if (rc) {
436 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800437 goto end;
438 }
439
Jeff Johnson7af334b2017-02-01 13:03:43 -0800440 /*
441 * OCB set config command successful.
442 * Open the TX data path
443 */
444 if (!hdd_ocb_register_sta(adapter))
445 wlan_hdd_netif_queue_control(adapter,
446 WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
447 WLAN_CONTROL_PATH);
448
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800449 /* fall through */
450end:
Jeff Johnson7af334b2017-02-01 13:03:43 -0800451 hdd_request_put(hdd_request);
452
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800453 return rc;
454}
455
456/**
457 * __iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED
458 * ioctl
459 * @dev: Pointer to net_device structure
460 * @iw_request_info: IW Request Info
461 * @wrqu: IW Request Userspace Data Pointer
462 * @extra: IW Request Kernel Data Pointer
463 *
464 * Return: 0 on success
465 */
466static int __iw_set_dot11p_channel_sched(struct net_device *dev,
467 struct iw_request_info *info,
468 union iwreq_data *wrqu, char *extra)
469{
Jeff Johnson441e1f72017-02-07 08:50:49 -0800470 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800471 struct dot11p_channel_sched *sched;
Jeff Johnson7106aba2017-08-28 11:49:07 -0700472 struct hdd_context *hdd_ctx;
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700473 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 struct sir_ocb_config *config = NULL;
475 uint8_t *mac_addr;
476 int i, j;
477 struct sir_ocb_config_channel *curr_chan;
478
Jeff Johnson6ee91ee2016-02-11 18:55:30 -0800479 ENTER_DEV(dev);
480
Jeff Johnson382bce02017-09-01 14:21:07 -0700481 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson441e1f72017-02-07 08:50:49 -0800482 rc = wlan_hdd_validate_context(hdd_ctx);
483 if (0 != rc)
484 return rc;
485
486 rc = hdd_check_private_wext_control(hdd_ctx, info);
487 if (0 != rc)
488 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800489
Krunal Sonibe766b02016-03-10 13:00:44 -0800490 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700491 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800492 return -EINVAL;
493 }
494
495 sched = (struct dot11p_channel_sched *)extra;
496
497 /* Scheduled slots same as num channels for compatibility */
498 config = hdd_ocb_config_new(sched->num_channels, sched->num_channels,
499 0, 0);
500 if (config == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700501 hdd_err("Failed to allocate memory!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502 return -ENOMEM;
503 }
504
505 /* Identify the vdev interface */
Jeff Johnson1b780e42017-10-31 14:11:45 -0700506 config->session_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507
508 /* Release all the mac addresses used for OCB */
509 for (i = 0; i < adapter->ocb_mac_addr_count; i++) {
Jeff Johnson399c6272017-08-30 10:51:00 -0700510 wlan_hdd_release_intf_addr(hdd_ctx,
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800511 adapter->ocb_mac_address[i].bytes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800512 }
513 adapter->ocb_mac_addr_count = 0;
514
515 config->channel_count = 0;
516 for (i = 0; i < sched->num_channels; i++) {
517 if (0 == sched->channels[i].channel_freq)
518 continue;
519
520 curr_chan = &(config->channels[config->channel_count]);
521
522 curr_chan->chan_freq = sched->channels[i].channel_freq;
523 /*
524 * tx_power is divided by 2 because ocb_channel.tx_power is
525 * in half dB increments and sir_ocb_config_channel.max_pwr
526 * is in 1 dB increments.
527 */
528 curr_chan->max_pwr = sched->channels[i].tx_power / 2;
529 curr_chan->bandwidth = sched->channels[i].channel_bandwidth;
530 /* assume 10 as default if not provided */
531 if (curr_chan->bandwidth == 0)
532 curr_chan->bandwidth = 10;
533
534 /*
535 * Setup locally administered mac addresses for each channel.
536 * First channel uses the adapter's address.
537 */
538 if (i == 0) {
Anurag Chouhanc5548422016-02-24 18:33:27 +0530539 qdf_copy_macaddr(&curr_chan->mac_address,
Jeff Johnson1e851a12017-10-28 14:36:12 -0700540 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800541 } else {
Jeff Johnson399c6272017-08-30 10:51:00 -0700542 mac_addr = wlan_hdd_get_intf_addr(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800543 if (mac_addr == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700544 hdd_err("Cannot obtain mac address");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800545 rc = -EINVAL;
546 goto fail;
547 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530548 qdf_mem_copy(config->channels[
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800549 config->channel_count].mac_address.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550 mac_addr, sizeof(tSirMacAddr));
551 /* Save the mac address to release later */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530552 qdf_mem_copy(adapter->ocb_mac_address[
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800553 adapter->ocb_mac_addr_count].bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530554 mac_addr, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800555 adapter->ocb_mac_addr_count++;
556 }
557
558 for (j = 0; j < MAX_NUM_AC; j++) {
559 curr_chan->qos_params[j].aifsn =
560 sched->channels[i].qos_params[j].aifsn;
561 curr_chan->qos_params[j].cwmin =
562 sched->channels[i].qos_params[j].cwmin;
563 curr_chan->qos_params[j].cwmax =
564 sched->channels[i].qos_params[j].cwmax;
565 }
566
567 config->channel_count++;
568 }
569
570 /*
571 * Scheduled slots same as num channels for compatibility with
572 * legacy use.
573 */
574 for (i = 0; i < sched->num_channels; i++) {
575 config->schedule[i].chan_freq = sched->channels[i].channel_freq;
576 config->schedule[i].guard_interval =
577 sched->channels[i].start_guard_interval;
578 config->schedule[i].total_duration =
579 sched->channels[i].duration;
580 }
581
582 rc = hdd_ocb_set_config_req(adapter, config);
583 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700584 hdd_err("Error while setting OCB config");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800585 goto fail;
586 }
587
588 rc = 0;
589
590fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530591 qdf_mem_free(config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800592 return rc;
593}
594
595/**
596 * iw_set_dot11p_channel_sched() - IOCTL interface for setting channel schedule
597 * @dev: Pointer to net_device structure
598 * @iw_request_info: IW Request Info
599 * @wrqu: IW Request Userspace Data Pointer
600 * @extra: IW Request Kernel Data Pointer
601 *
602 * Return: 0 on success.
603 */
604int iw_set_dot11p_channel_sched(struct net_device *dev,
605 struct iw_request_info *info,
606 union iwreq_data *wrqu, char *extra)
607{
608 int ret;
609
610 cds_ssr_protect(__func__);
611 ret = __iw_set_dot11p_channel_sched(dev, info, wrqu, extra);
612 cds_ssr_unprotect(__func__);
613
614 return ret;
615}
616
617static const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[
618 QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1] = {
619 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT] = {
620 .type = NLA_U32
621 },
622 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE] = {
623 .type = NLA_U32
624 },
625 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY] = {
626 .type = NLA_BINARY
627 },
628 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY] = {
629 .type = NLA_BINARY
630 },
631 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY] = {
632 .type = NLA_BINARY
633 },
634 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY] = {
635 .type = NLA_BINARY
636 },
637 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS] = {
638 .type = NLA_U32
639 },
640};
641
642static const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[
643 QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1] = {
644 [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE] = {
645 .type = NLA_BINARY, .len = SIZE_UTC_TIME
646 },
647 [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR] = {
648 .type = NLA_BINARY, .len = SIZE_UTC_TIME_ERROR
649 },
650};
651
652static const struct nla_policy qca_wlan_vendor_ocb_start_timing_advert_policy[
653 QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1] = {
654 [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ] = {
655 .type = NLA_U32
656 },
657 [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE] = {
658 .type = NLA_U32
659 },
660};
661
662static const struct nla_policy qca_wlan_vendor_ocb_stop_timing_advert_policy[
663 QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1] = {
664 [QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ] = {
665 .type = NLA_U32
666 },
667};
668
669static const struct nla_policy qca_wlan_vendor_ocb_get_tsf_timer_resp[] = {
670 [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH] = {
671 .type = NLA_U32
672 },
673 [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW] = {
674 .type = NLA_U32
675 },
676};
677
678static const struct nla_policy qca_wlan_vendor_dcc_get_stats[] = {
679 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] = {
680 .type = NLA_U32
681 },
682 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY] = {
683 .type = NLA_BINARY
684 },
685};
686
687static const struct nla_policy qca_wlan_vendor_dcc_get_stats_resp[] = {
688 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT] = {
689 .type = NLA_U32
690 },
691 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY] = {
692 .type = NLA_BINARY
693 },
694};
695
696static const struct nla_policy qca_wlan_vendor_dcc_clear_stats[] = {
697 [QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP] = {
698 .type = NLA_U32
699 },
700};
701
702static const struct nla_policy qca_wlan_vendor_dcc_update_ndl[
703 QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1] = {
704 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] = {
705 .type = NLA_U32
706 },
707 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] = {
708 .type = NLA_BINARY
709 },
710 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY] = {
711 .type = NLA_BINARY
712 },
713};
714
715/**
716 * struct wlan_hdd_ocb_config_channel
717 * @chan_freq: frequency of the channel
718 * @bandwidth: bandwidth of the channel, either 10 or 20 MHz
719 * @mac_address: MAC address assigned to this channel
720 * @qos_params: QoS parameters
721 * @max_pwr: maximum transmit power of the channel (1/2 dBm)
722 * @min_pwr: minimum transmit power of the channel (1/2 dBm)
723 */
724struct wlan_hdd_ocb_config_channel {
725 uint32_t chan_freq;
726 uint32_t bandwidth;
727 uint16_t flags;
728 uint8_t reserved[4];
729 struct sir_qos_params qos_params[MAX_NUM_AC];
730 uint32_t max_pwr;
731 uint32_t min_pwr;
732};
733
734static void wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel(
735 struct sir_ocb_config_channel *dest,
736 struct wlan_hdd_ocb_config_channel *src,
737 uint32_t channel_count)
738{
739 uint32_t i;
740
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530741 qdf_mem_zero(dest, channel_count * sizeof(*dest));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742
743 for (i = 0; i < channel_count; i++) {
744 dest[i].chan_freq = src[i].chan_freq;
745 dest[i].bandwidth = src[i].bandwidth;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530746 qdf_mem_copy(dest[i].qos_params, src[i].qos_params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800747 sizeof(dest[i].qos_params));
748 /*
749 * max_pwr and min_pwr are divided by 2 because
750 * wlan_hdd_ocb_config_channel.max_pwr and min_pwr
751 * are in 1/2 dB increments and
752 * sir_ocb_config_channel.max_pwr and min_pwr are in
753 * 1 dB increments.
754 */
755 dest[i].max_pwr = src[i].max_pwr / 2;
756 dest[i].min_pwr = (src[i].min_pwr + 1) / 2;
757 dest[i].flags = src[i].flags;
758 }
759}
760
761/**
762 * __wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command
763 * @wiphy: pointer to the wiphy
764 * @wdev: pointer to the wdev
765 * @data: The netlink data
766 * @data_len: The length of the netlink data in bytes
767 *
768 * Return: 0 on success.
769 */
770static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy,
771 struct wireless_dev *wdev,
772 const void *data,
773 int data_len)
774{
Jeff Johnson7106aba2017-08-28 11:49:07 -0700775 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800776 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700777 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800778 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1];
779 struct nlattr *channel_array;
780 struct nlattr *sched_array;
781 struct nlattr *ndl_chan_list;
782 uint32_t ndl_chan_list_len;
783 struct nlattr *ndl_active_state_list;
784 uint32_t ndl_active_state_list_len;
785 uint32_t flags = 0;
786 int i;
Jeff Johnson929ad032016-10-19 07:34:42 -0700787 uint32_t channel_count, schedule_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800788 struct sir_ocb_config *config;
789 int rc = -EINVAL;
790 uint8_t *mac_addr;
791
Jeff Johnson1f61b612016-02-12 16:28:33 -0800792 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530794 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800795 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800796
Krunal Sonibe766b02016-03-10 13:00:44 -0800797 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700798 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800799 return -EINVAL;
800 }
801
802 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -0800803 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX,
804 data, data_len,
805 qca_wlan_vendor_ocb_set_config_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700806 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800807 return -EINVAL;
808 }
809
810 /* Get the number of channels in the schedule */
811 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700812 hdd_err("CHANNEL_COUNT is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800813 return -EINVAL;
814 }
815 channel_count = nla_get_u32(
816 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]);
817
818 /* Get the size of the channel schedule */
819 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700820 hdd_err("SCHEDULE_SIZE is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800821 return -EINVAL;
822 }
823 schedule_size = nla_get_u32(
824 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]);
825
826 /* Get the ndl chan array and the ndl active state array. */
SaidiReddy Yenuga3db38772017-03-28 15:18:56 +0530827 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY]) {
828 hdd_err("NDL_CHANNEL_ARRAY is not present");
829 return -EINVAL;
830 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831 ndl_chan_list =
832 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY];
833 ndl_chan_list_len = (ndl_chan_list ? nla_len(ndl_chan_list) : 0);
834
SaidiReddy Yenuga3db38772017-03-28 15:18:56 +0530835 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY]) {
836 hdd_err("NDL_ACTIVE_STATE_ARRAY is not present");
837 return -EINVAL;
838 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800839 ndl_active_state_list =
840 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY];
841 ndl_active_state_list_len = (ndl_active_state_list ?
842 nla_len(ndl_active_state_list) : 0);
843
844 /* Get the flags */
845 if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS])
846 flags = nla_get_u32(tb[
847 QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]);
848
849 config = hdd_ocb_config_new(channel_count, schedule_size,
850 ndl_chan_list_len,
851 ndl_active_state_list_len);
852 if (config == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700853 hdd_err("Failed to allocate memory!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 return -ENOMEM;
855 }
856
857 config->channel_count = channel_count;
858 config->schedule_size = schedule_size;
859 config->flags = flags;
860
861 /* Read the channel array */
862 channel_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY];
863 if (!channel_array) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700864 hdd_err("No channel present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800865 goto fail;
866 }
867 if (nla_len(channel_array) != channel_count *
868 sizeof(struct wlan_hdd_ocb_config_channel)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700869 hdd_err("CHANNEL_ARRAY is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800870 goto fail;
871 }
872 wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel(
873 config->channels, nla_data(channel_array), channel_count);
874
875 /* Identify the vdev interface */
Jeff Johnson1b780e42017-10-31 14:11:45 -0700876 config->session_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800877
878 /* Release all the mac addresses used for OCB */
879 for (i = 0; i < adapter->ocb_mac_addr_count; i++) {
Jeff Johnson399c6272017-08-30 10:51:00 -0700880 wlan_hdd_release_intf_addr(hdd_ctx,
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800881 adapter->ocb_mac_address[i].bytes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882 }
883 adapter->ocb_mac_addr_count = 0;
884
885 /*
886 * Setup locally administered mac addresses for each channel.
887 * First channel uses the adapter's address.
888 */
889 for (i = 0; i < config->channel_count; i++) {
890 if (i == 0) {
Anurag Chouhanc5548422016-02-24 18:33:27 +0530891 qdf_copy_macaddr(&config->channels[i].mac_address,
Jeff Johnson1e851a12017-10-28 14:36:12 -0700892 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800893 } else {
Jeff Johnson399c6272017-08-30 10:51:00 -0700894 mac_addr = wlan_hdd_get_intf_addr(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800895 if (mac_addr == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700896 hdd_err("Cannot obtain mac address");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800897 goto fail;
898 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530899 qdf_mem_copy(config->channels[i].mac_address.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530900 mac_addr, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800901 /* Save the mac address to release later */
Anurag Chouhanc5548422016-02-24 18:33:27 +0530902 qdf_copy_macaddr(&adapter->ocb_mac_address[
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800903 adapter->ocb_mac_addr_count],
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800904 &config->channels[i].mac_address);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800905 adapter->ocb_mac_addr_count++;
906 }
907 }
908
909 /* Read the schedule array */
910 sched_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY];
911 if (!sched_array) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700912 hdd_err("No channel present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800913 goto fail;
914 }
915 if (nla_len(sched_array) != schedule_size * sizeof(*config->schedule)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700916 hdd_err("SCHEDULE_ARRAY is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 goto fail;
918 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530919 qdf_mem_copy(config->schedule, nla_data(sched_array),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800920 nla_len(sched_array));
921
922 /* Copy the NDL chan array */
923 if (ndl_chan_list_len) {
924 config->dcc_ndl_chan_list_len = ndl_chan_list_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530925 qdf_mem_copy(config->dcc_ndl_chan_list, nla_data(ndl_chan_list),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800926 nla_len(ndl_chan_list));
927 }
928
929 /* Copy the NDL active state array */
930 if (ndl_active_state_list_len) {
931 config->dcc_ndl_active_state_list_len =
932 ndl_active_state_list_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530933 qdf_mem_copy(config->dcc_ndl_active_state_list,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800934 nla_data(ndl_active_state_list),
935 nla_len(ndl_active_state_list));
936 }
937
938 rc = hdd_ocb_set_config_req(adapter, config);
939 if (rc)
Jeff Johnson5f735d52016-07-06 15:14:45 -0700940 hdd_err("Error while setting OCB config: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800941
942fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530943 qdf_mem_free(config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800944 return rc;
945}
946
947/**
948 * wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command
949 * @wiphy: pointer to the wiphy
950 * @wdev: pointer to the wdev
951 * @data: The netlink data
952 * @data_len: The length of the netlink data in bytes
953 *
954 * Return: 0 on success.
955 */
956int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy,
957 struct wireless_dev *wdev,
958 const void *data,
959 int data_len)
960{
961 int ret;
962
963 cds_ssr_protect(__func__);
964 ret = __wlan_hdd_cfg80211_ocb_set_config(wiphy, wdev, data, data_len);
965 cds_ssr_unprotect(__func__);
966
967 return ret;
968}
969
970/**
971 * __wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for set UTC time command
972 * @wiphy: pointer to the wiphy
973 * @wdev: pointer to the wdev
974 * @data: The netlink data
975 * @data_len: The length of the netlink data in bytes
976 *
977 * Return: 0 on success.
978 */
979static int __wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy,
980 struct wireless_dev *wdev,
981 const void *data,
982 int data_len)
983{
Jeff Johnson7106aba2017-08-28 11:49:07 -0700984 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800985 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -0700986 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1];
988 struct nlattr *utc_attr;
989 struct nlattr *time_error_attr;
990 struct sir_ocb_utc *utc;
991 int rc = -EINVAL;
992
Jeff Johnson1f61b612016-02-12 16:28:33 -0800993 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800994
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530995 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800996 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800997
Krunal Sonibe766b02016-03-10 13:00:44 -0800998 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700999 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001000 return -EINVAL;
1001 }
1002
Jeff Johnson1b780e42017-10-31 14:11:45 -07001003 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001004 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001005 return -EINVAL;
1006 }
1007
1008 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001009 if (wlan_cfg80211_nla_parse(tb,
1010 QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX,
1011 data, data_len,
1012 qca_wlan_vendor_ocb_set_utc_time_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001013 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001014 return -EINVAL;
1015 }
1016
1017 /* Read the UTC time */
1018 utc_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE];
1019 if (!utc_attr) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001020 hdd_err("UTC_TIME is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001021 return -EINVAL;
1022 }
1023 if (nla_len(utc_attr) != SIZE_UTC_TIME) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001024 hdd_err("UTC_TIME is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001025 return -EINVAL;
1026 }
1027
1028 /* Read the time error */
1029 time_error_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR];
1030 if (!time_error_attr) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001031 hdd_err("UTC_TIME is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 return -EINVAL;
1033 }
1034 if (nla_len(time_error_attr) != SIZE_UTC_TIME_ERROR) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001035 hdd_err("UTC_TIME is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001036 return -EINVAL;
1037 }
1038
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301039 utc = qdf_mem_malloc(sizeof(*utc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001040 if (!utc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001041 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001042 return -ENOMEM;
1043 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07001044 utc->vdev_id = adapter->session_id;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301045 qdf_mem_copy(utc->utc_time, nla_data(utc_attr), SIZE_UTC_TIME);
1046 qdf_mem_copy(utc->time_error, nla_data(time_error_attr),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001047 SIZE_UTC_TIME_ERROR);
1048
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301049 if (sme_ocb_set_utc_time(hdd_ctx->hHal, utc) != QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001050 hdd_err("Error while setting UTC time");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001051 rc = -EINVAL;
1052 } else {
1053 rc = 0;
1054 }
1055
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301056 qdf_mem_free(utc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001057 return rc;
1058}
1059
1060/**
1061 * wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for the set UTC time command
1062 * @wiphy: pointer to the wiphy
1063 * @wdev: pointer to the wdev
1064 * @data: The netlink data
1065 * @data_len: The length of the netlink data in bytes
1066 *
1067 * Return: 0 on success.
1068 */
1069int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy,
1070 struct wireless_dev *wdev,
1071 const void *data,
1072 int data_len)
1073{
1074 int ret;
1075
1076 cds_ssr_protect(__func__);
1077 ret = __wlan_hdd_cfg80211_ocb_set_utc_time(wiphy, wdev, data, data_len);
1078 cds_ssr_unprotect(__func__);
1079
1080 return ret;
1081}
1082
1083/**
1084 * __wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for start TA cmd
1085 * @wiphy: pointer to the wiphy
1086 * @wdev: pointer to the wdev
1087 * @data: The netlink data
1088 * @data_len: The length of the netlink data in bytes
1089 *
1090 * Return: 0 on success.
1091 */
1092static int
1093__wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy,
1094 struct wireless_dev *wdev,
1095 const void *data,
1096 int data_len)
1097{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001098 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001099 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001100 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001101 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1];
1102 struct sir_ocb_timing_advert *timing_advert;
1103 int rc = -EINVAL;
1104
Jeff Johnson1f61b612016-02-12 16:28:33 -08001105 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001106
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301107 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001109
Krunal Sonibe766b02016-03-10 13:00:44 -08001110 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001111 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001112 return -EINVAL;
1113 }
1114
Jeff Johnson1b780e42017-10-31 14:11:45 -07001115 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001116 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 return -EINVAL;
1118 }
1119
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301120 timing_advert = qdf_mem_malloc(sizeof(*timing_advert));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121 if (!timing_advert) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001122 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001123 return -ENOMEM;
1124 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07001125 timing_advert->vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001126
1127 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001128 if (wlan_cfg80211_nla_parse(tb,
1129 QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX,
1130 data, data_len,
1131 qca_wlan_vendor_ocb_start_timing_advert_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001132 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001133 goto fail;
1134 }
1135
1136 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001137 hdd_err("CHANNEL_FREQ is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001138 goto fail;
1139 }
1140 timing_advert->chan_freq = nla_get_u32(
1141 tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]);
1142
1143 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001144 hdd_err("REPEAT_RATE is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001145 goto fail;
1146 }
1147 timing_advert->repeat_rate = nla_get_u32(
1148 tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]);
1149
1150 timing_advert->template_length =
Naveen Rawatb4d37622015-11-13 16:15:25 -08001151 sme_ocb_gen_timing_advert_frame(hdd_ctx->hHal,
Jeff Johnson1e851a12017-10-28 14:36:12 -07001152 *(tSirMacAddr *)&adapter->mac_addr.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001153 &timing_advert->template_value,
1154 &timing_advert->timestamp_offset,
1155 &timing_advert->time_value_offset);
1156 if (timing_advert->template_length <= 0) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001157 hdd_err("Error while generating the TA frame");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001158 goto fail;
1159 }
1160
1161 if (sme_ocb_start_timing_advert(hdd_ctx->hHal, timing_advert) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301162 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001163 hdd_err("Error while starting timing advert");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001164 rc = -EINVAL;
1165 } else {
1166 rc = 0;
1167 }
1168
1169fail:
1170 if (timing_advert->template_value)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301171 qdf_mem_free(timing_advert->template_value);
1172 qdf_mem_free(timing_advert);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001173 return rc;
1174}
1175
1176/**
1177 * wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for the start TA cmd
1178 * @wiphy: pointer to the wiphy
1179 * @wdev: pointer to the wdev
1180 * @data: The netlink data
1181 * @data_len: The length of the netlink data in bytes
1182 *
1183 * Return: 0 on success.
1184 */
1185int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy,
1186 struct wireless_dev *wdev,
1187 const void *data,
1188 int data_len)
1189{
1190 int ret;
1191
1192 cds_ssr_protect(__func__);
1193 ret = __wlan_hdd_cfg80211_ocb_start_timing_advert(wiphy, wdev,
1194 data, data_len);
1195 cds_ssr_unprotect(__func__);
1196
1197 return ret;
1198}
1199
1200/**
1201 * __wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd
1202 * @wiphy: pointer to the wiphy
1203 * @wdev: pointer to the wdev
1204 * @data: The netlink data
1205 * @data_len: The length of the netlink data in bytes
1206 *
1207 * Return: 0 on success.
1208 */
1209static int
1210__wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy,
1211 struct wireless_dev *wdev,
1212 const void *data,
1213 int data_len)
1214{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001215 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001217 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001218 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1];
1219 struct sir_ocb_timing_advert *timing_advert;
1220 int rc = -EINVAL;
1221
Jeff Johnson1f61b612016-02-12 16:28:33 -08001222 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001223
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301224 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001225 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001226
Krunal Sonibe766b02016-03-10 13:00:44 -08001227 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001228 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001229 return -EINVAL;
1230 }
1231
Jeff Johnson1b780e42017-10-31 14:11:45 -07001232 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001233 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001234 return -EINVAL;
1235 }
1236
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301237 timing_advert = qdf_mem_malloc(sizeof(*timing_advert));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001238 if (!timing_advert) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001239 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240 return -ENOMEM;
1241 }
Jeff Johnson1b780e42017-10-31 14:11:45 -07001242 timing_advert->vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001243
1244 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001245 if (wlan_cfg80211_nla_parse(tb,
1246 QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX,
1247 data, data_len,
1248 qca_wlan_vendor_ocb_stop_timing_advert_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001249 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001250 goto fail;
1251 }
1252
1253 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001254 hdd_err("CHANNEL_FREQ is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001255 goto fail;
1256 }
1257 timing_advert->chan_freq = nla_get_u32(
1258 tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]);
1259
1260 if (sme_ocb_stop_timing_advert(hdd_ctx->hHal, timing_advert) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301261 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001262 hdd_err("Error while stopping timing advert");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001263 rc = -EINVAL;
1264 } else {
1265 rc = 0;
1266 }
1267
1268fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301269 qdf_mem_free(timing_advert);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001270 return rc;
1271}
1272
1273/**
1274 * wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd
1275 * @wiphy: pointer to the wiphy
1276 * @wdev: pointer to the wdev
1277 * @data: The netlink data
1278 * @data_len: The length of the netlink data in bytes
1279 *
1280 * Return: 0 on success.
1281 */
1282int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy,
1283 struct wireless_dev *wdev,
1284 const void *data,
1285 int data_len)
1286{
1287 int ret;
1288
1289 cds_ssr_protect(__func__);
1290 ret = __wlan_hdd_cfg80211_ocb_stop_timing_advert(wiphy, wdev,
1291 data, data_len);
1292 cds_ssr_unprotect(__func__);
1293
1294 return ret;
1295}
1296
Jeff Johnson7af334b2017-02-01 13:03:43 -08001297struct hdd_ocb_get_tsf_timer_priv {
1298 struct sir_ocb_get_tsf_timer_response response;
1299 int status;
1300};
1301
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001302/**
1303 * hdd_ocb_get_tsf_timer_callback() - Callback to get TSF command
1304 * @context_ptr: request context
1305 * @response_ptr: response data
1306 */
1307static void hdd_ocb_get_tsf_timer_callback(void *context_ptr,
1308 void *response_ptr)
1309{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001310 struct hdd_request *hdd_request;
1311 struct hdd_ocb_get_tsf_timer_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001312 struct sir_ocb_get_tsf_timer_response *response = response_ptr;
1313
Jeff Johnson7af334b2017-02-01 13:03:43 -08001314 hdd_request = hdd_request_get(context_ptr);
1315 if (!hdd_request) {
1316 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001317 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001318 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001319
1320 if (response) {
1321 priv->response = *response;
1322 priv->status = 0;
1323 } else {
1324 priv->status = -EINVAL;
1325 }
1326 hdd_request_complete(hdd_request);
1327 hdd_request_put(hdd_request);
1328}
1329
1330static int
1331hdd_ocb_get_tsf_timer_reply(struct wiphy *wiphy,
1332 struct sir_ocb_get_tsf_timer_response *response)
1333{
1334 uint32_t nl_buf_len;
1335 struct sk_buff *nl_resp;
1336 int rc;
1337
1338 /* Allocate the buffer for the response. */
1339 nl_buf_len = NLMSG_HDRLEN;
1340 nl_buf_len += 2 * (NLA_HDRLEN + sizeof(uint32_t));
1341 nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
1342 if (!nl_resp) {
1343 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
1344 return -ENOMEM;
1345 }
1346
1347 /* Populate the response. */
1348 rc = nla_put_u32(nl_resp,
1349 QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH,
1350 response->timer_high);
1351 if (rc)
1352 goto end;
1353 rc = nla_put_u32(nl_resp,
1354 QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW,
1355 response->timer_low);
1356 if (rc)
1357 goto end;
1358
1359 /* Send the response. */
1360 rc = cfg80211_vendor_cmd_reply(nl_resp);
1361 nl_resp = NULL;
1362 if (rc) {
1363 hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc);
1364 goto end;
1365 }
1366end:
1367 if (nl_resp)
1368 kfree_skb(nl_resp);
1369
1370 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001371}
1372
1373/**
1374 * __wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd
1375 * @wiphy: pointer to the wiphy
1376 * @wdev: pointer to the wdev
1377 * @data: The netlink data
1378 * @data_len: The length of the netlink data in bytes
1379 *
1380 * Return: 0 on success.
1381 */
1382static int
1383__wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy,
1384 struct wireless_dev *wdev,
1385 const void *data,
1386 int data_len)
1387{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001388 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001389 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001390 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson7af334b2017-02-01 13:03:43 -08001391 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001392 struct sir_ocb_get_tsf_timer request = {0};
Jeff Johnson7af334b2017-02-01 13:03:43 -08001393 QDF_STATUS status;
1394 void *cookie;
1395 struct hdd_request *hdd_request;
1396 struct hdd_ocb_get_tsf_timer_priv *priv;
1397 static const struct hdd_request_params params = {
1398 .priv_size = sizeof(*priv),
1399 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1400 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001401
Jeff Johnson1f61b612016-02-12 16:28:33 -08001402 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001403
Jeff Johnson7af334b2017-02-01 13:03:43 -08001404 rc = wlan_hdd_validate_context(hdd_ctx);
1405 if (rc)
1406 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001407
Krunal Sonibe766b02016-03-10 13:00:44 -08001408 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001409 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001410 return -EINVAL;
1411 }
1412
Jeff Johnson1b780e42017-10-31 14:11:45 -07001413 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001414 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001415 return -EINVAL;
1416 }
1417
Jeff Johnson7af334b2017-02-01 13:03:43 -08001418 hdd_request = hdd_request_alloc(&params);
1419 if (!hdd_request) {
1420 hdd_err("Request allocation failure");
1421 return -ENOMEM;
1422 }
1423 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001424
Jeff Johnson1b780e42017-10-31 14:11:45 -07001425 request.vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001426 /* Call the SME function */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001427 status = sme_ocb_get_tsf_timer(hdd_ctx->hHal, cookie,
1428 hdd_ocb_get_tsf_timer_callback,
1429 &request);
1430 if (QDF_IS_STATUS_ERROR(status)) {
1431 hdd_err("Error calling SME function.");
1432 rc = qdf_status_to_os_return(status);
1433 goto end;
1434 }
1435
1436 rc = hdd_request_wait_for_response(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001437 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001438 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001439 goto end;
1440 }
1441
Jeff Johnson7af334b2017-02-01 13:03:43 -08001442 priv = hdd_request_priv(hdd_request);
1443 rc = priv->status;
1444 if (rc) {
1445 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001446 goto end;
1447 }
1448
Varun Reddy Yeturu8a5d3d42017-08-02 13:03:27 -07001449 hdd_debug("Got TSF timer response, high=%d, low=%d",
Jeff Johnson7af334b2017-02-01 13:03:43 -08001450 priv->response.timer_high,
1451 priv->response.timer_low);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001452
1453 /* Send the response. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001454 rc = hdd_ocb_get_tsf_timer_reply(wiphy, &priv->response);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001455 if (rc) {
Jeff Johnson7af334b2017-02-01 13:03:43 -08001456 hdd_err("hdd_ocb_get_tsf_timer_reply failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001457 goto end;
1458 }
1459
Jeff Johnson7af334b2017-02-01 13:03:43 -08001460 /* fall through */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001461end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001462 hdd_request_put(hdd_request);
1463
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001464 return rc;
1465}
1466
1467/**
1468 * wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd
1469 * @wiphy: pointer to the wiphy
1470 * @wdev: pointer to the wdev
1471 * @data: The netlink data
1472 * @data_len: The length of the netlink data in bytes
1473 *
1474 * Return: 0 on success.
1475 */
1476int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy,
1477 struct wireless_dev *wdev,
1478 const void *data,
1479 int data_len)
1480{
1481 int ret;
1482
1483 cds_ssr_protect(__func__);
1484 ret = __wlan_hdd_cfg80211_ocb_get_tsf_timer(wiphy, wdev,
1485 data, data_len);
1486 cds_ssr_unprotect(__func__);
1487
1488 return ret;
1489}
1490
Jeff Johnson7af334b2017-02-01 13:03:43 -08001491struct hdd_dcc_stats_priv {
1492 struct sir_dcc_get_stats_response *response;
1493 int status;
1494};
1495
1496static void hdd_dcc_get_stats_dealloc(void *context_ptr)
1497{
1498 struct hdd_dcc_stats_priv *priv = context_ptr;
1499
1500 qdf_mem_free(priv->response);
1501 priv->response = NULL;
1502}
1503
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001504/**
1505 * hdd_dcc_get_stats_callback() - Callback to get stats command
1506 * @context_ptr: request context
1507 * @response_ptr: response data
1508 */
1509static void hdd_dcc_get_stats_callback(void *context_ptr, void *response_ptr)
1510{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001511 struct hdd_request *hdd_request;
1512 struct hdd_dcc_stats_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001513 struct sir_dcc_get_stats_response *response = response_ptr;
1514 struct sir_dcc_get_stats_response *hdd_resp;
1515
Jeff Johnson7af334b2017-02-01 13:03:43 -08001516 hdd_request = hdd_request_get(context_ptr);
1517 if (!hdd_request) {
1518 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001519 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001520 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001521
1522 priv = hdd_request_priv(hdd_request);
1523 if (!response) {
1524 priv->status = -EINVAL;
1525 goto end;
1526 }
1527
1528 priv->response = qdf_mem_malloc(sizeof(*response) +
1529 response->channel_stats_array_len);
1530 if (!priv->response) {
1531 priv->status = -ENOMEM;
1532 goto end;
1533 }
1534
1535 hdd_resp = priv->response;
1536 *hdd_resp = *response;
1537 hdd_resp->channel_stats_array = (void *)hdd_resp + sizeof(*hdd_resp);
1538 qdf_mem_copy(hdd_resp->channel_stats_array,
1539 response->channel_stats_array,
1540 response->channel_stats_array_len);
1541 priv->status = 0;
1542
1543end:
1544 hdd_request_complete(hdd_request);
1545 hdd_request_put(hdd_request);
1546}
1547
1548static int
1549hdd_dcc_get_stats_send_reply(struct wiphy *wiphy,
1550 struct sir_dcc_get_stats_response *response)
1551{
1552 uint32_t nl_buf_len;
1553 struct sk_buff *nl_resp;
1554 int rc;
1555
1556 /* Allocate the buffer for the response. */
1557 nl_buf_len = NLMSG_HDRLEN;
1558 nl_buf_len += NLA_HDRLEN + sizeof(uint32_t);
1559 nl_buf_len += NLA_HDRLEN + response->channel_stats_array_len;
1560 nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
1561 if (!nl_resp) {
1562 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
1563 return -ENOMEM;
1564 }
1565
1566 /* Populate the response. */
1567 rc = nla_put_u32(nl_resp,
1568 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT,
1569 response->num_channels);
1570 if (rc)
1571 goto end;
1572 rc = nla_put(nl_resp,
1573 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY,
1574 response->channel_stats_array_len,
1575 response->channel_stats_array);
1576 if (rc)
1577 goto end;
1578
1579 /* Send the response. */
1580 rc = cfg80211_vendor_cmd_reply(nl_resp);
1581 nl_resp = NULL;
1582 if (rc) {
1583 hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc);
1584 goto end;
1585 }
1586end:
1587 if (nl_resp)
1588 kfree_skb(nl_resp);
1589
1590 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001591}
1592
1593/**
1594 * __wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats
1595 * @wiphy: pointer to the wiphy
1596 * @wdev: pointer to the wdev
1597 * @data: The netlink data
1598 * @data_len: The length of the netlink data in bytes
1599 *
1600 * Return: 0 on success.
1601 */
1602static int __wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy,
1603 struct wireless_dev *wdev,
1604 const void *data,
1605 int data_len)
1606{
1607 uint32_t channel_count = 0;
1608 uint32_t request_array_len = 0;
1609 void *request_array = 0;
Jeff Johnson7106aba2017-08-28 11:49:07 -07001610 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001611 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001612 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001613 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX + 1];
Jeff Johnson7af334b2017-02-01 13:03:43 -08001614 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615 struct sir_dcc_get_stats request = {0};
Jeff Johnson7af334b2017-02-01 13:03:43 -08001616 QDF_STATUS status;
1617 void *cookie;
1618 struct hdd_request *hdd_request;
1619 struct hdd_dcc_stats_priv *priv;
1620 static const struct hdd_request_params params = {
1621 .priv_size = sizeof(*priv),
1622 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1623 .dealloc = hdd_dcc_get_stats_dealloc,
1624 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001625
Jeff Johnson1f61b612016-02-12 16:28:33 -08001626 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001627
Jeff Johnson7af334b2017-02-01 13:03:43 -08001628 rc = wlan_hdd_validate_context(hdd_ctx);
1629 if (rc)
1630 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001631
Krunal Sonibe766b02016-03-10 13:00:44 -08001632 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001633 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001634 return -EINVAL;
1635 }
1636
Jeff Johnson1b780e42017-10-31 14:11:45 -07001637 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001638 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001639 return -EINVAL;
1640 }
1641
1642 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001643 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX,
1644 data, data_len,
1645 qca_wlan_vendor_dcc_get_stats)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001646 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001647 return -EINVAL;
1648 }
1649
1650 /* Validate all the parameters are present */
1651 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] ||
1652 !tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001653 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001654 return -EINVAL;
1655 }
1656
1657 channel_count = nla_get_u32(
1658 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT]);
1659 request_array_len = nla_len(
1660 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]);
1661 request_array = nla_data(
1662 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]);
1663
Jeff Johnson7af334b2017-02-01 13:03:43 -08001664 hdd_request = hdd_request_alloc(&params);
1665 if (!hdd_request) {
1666 hdd_err("Request allocation failure");
1667 return -ENOMEM;
1668 }
1669 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001670
Jeff Johnson1b780e42017-10-31 14:11:45 -07001671 request.vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001672 request.channel_count = channel_count;
1673 request.request_array_len = request_array_len;
1674 request.request_array = request_array;
1675
1676 /* Call the SME function. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001677 status = sme_dcc_get_stats(hdd_ctx->hHal, cookie,
1678 hdd_dcc_get_stats_callback,
1679 &request);
1680 if (QDF_IS_STATUS_ERROR(status)) {
1681 hdd_err("Error calling SME function.");
1682 rc = qdf_status_to_os_return(status);
1683 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001684 }
1685
1686 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001687 rc = hdd_request_wait_for_response(hdd_request);
1688 if (rc) {
1689 hdd_err("Operation timed out");
1690 goto end;
1691 }
1692
1693 priv = hdd_request_priv(hdd_request);
1694 rc = priv->status;
1695 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001696 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001697 goto end;
1698 }
1699
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001700 /* Send the response. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001701 rc = hdd_dcc_get_stats_send_reply(wiphy, priv->response);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702 if (rc) {
Jeff Johnson7af334b2017-02-01 13:03:43 -08001703 hdd_err("hdd_dcc_get_stats_send_reply failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001704 goto end;
1705 }
1706
1707 /* fall through */
1708end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001709 hdd_request_put(hdd_request);
1710
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001711 return rc;
1712}
1713
1714/**
1715 * wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats
1716 * @wiphy: pointer to the wiphy
1717 * @wdev: pointer to the wdev
1718 * @data: The netlink data
1719 * @data_len: The length of the netlink data in bytes
1720 *
1721 * Return: 0 on success.
1722 */
1723int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy,
1724 struct wireless_dev *wdev,
1725 const void *data,
1726 int data_len)
1727{
1728 int ret;
1729
1730 cds_ssr_protect(__func__);
1731 ret = __wlan_hdd_cfg80211_dcc_get_stats(wiphy, wdev,
1732 data, data_len);
1733 cds_ssr_unprotect(__func__);
1734
1735 return ret;
1736}
1737
1738/**
1739 * __wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd
1740 * @wiphy: pointer to the wiphy
1741 * @wdev: pointer to the wdev
1742 * @data: The netlink data
1743 * @data_len: The length of the netlink data in bytes
1744 *
1745 * Return: 0 on success.
1746 */
1747static int __wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy,
1748 struct wireless_dev *wdev,
1749 const void *data,
1750 int data_len)
1751{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001752 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001753 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001754 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX + 1];
1756
Jeff Johnson1f61b612016-02-12 16:28:33 -08001757 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001758
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301759 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001761
Krunal Sonibe766b02016-03-10 13:00:44 -08001762 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001763 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001764 return -EINVAL;
1765 }
1766
Jeff Johnson1b780e42017-10-31 14:11:45 -07001767 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001768 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769 return -EINVAL;
1770 }
1771
1772 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001773 if (wlan_cfg80211_nla_parse(tb,
1774 QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX,
1775 data, data_len,
1776 qca_wlan_vendor_dcc_clear_stats)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001777 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001778 return -EINVAL;
1779 }
1780
1781 /* Verify that the parameter is present */
1782 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001783 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784 return -EINVAL;
1785 }
1786
1787 /* Call the SME function */
Jeff Johnson1b780e42017-10-31 14:11:45 -07001788 if (sme_dcc_clear_stats(hdd_ctx->hHal, adapter->session_id,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001789 nla_get_u32(
1790 tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP])) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301791 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001792 hdd_err("Error calling SME function.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001793 return -EINVAL;
1794 }
1795
1796 return 0;
1797}
1798
1799/**
1800 * wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd
1801 * @wiphy: pointer to the wiphy
1802 * @wdev: pointer to the wdev
1803 * @data: The netlink data
1804 * @data_len: The length of the netlink data in bytes
1805 *
1806 * Return: 0 on success.
1807 */
1808int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy,
1809 struct wireless_dev *wdev,
1810 const void *data,
1811 int data_len)
1812{
1813 int ret;
1814
1815 cds_ssr_protect(__func__);
1816 ret = __wlan_hdd_cfg80211_dcc_clear_stats(wiphy, wdev,
1817 data, data_len);
1818 cds_ssr_unprotect(__func__);
1819
1820 return ret;
1821}
1822
Jeff Johnson7af334b2017-02-01 13:03:43 -08001823struct hdd_dcc_update_ndl_priv {
1824 int status;
1825};
1826
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001827/**
1828 * hdd_dcc_update_ndl_callback() - Callback to update NDL command
1829 * @context_ptr: request context
1830 * @response_ptr: response data
1831 */
1832static void hdd_dcc_update_ndl_callback(void *context_ptr, void *response_ptr)
1833{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001834 struct hdd_request *hdd_request;
1835 struct hdd_dcc_update_ndl_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001836 struct sir_dcc_update_ndl_response *response = response_ptr;
1837
Jeff Johnson7af334b2017-02-01 13:03:43 -08001838 hdd_request = hdd_request_get(context_ptr);
1839 if (!hdd_request) {
1840 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001841 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001842 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001843 priv = hdd_request_priv(hdd_request);
1844 if (response && (0 == response->status)) {
1845 priv->status = 0;
1846 } else {
1847 priv->status = -EINVAL;
1848 }
1849 hdd_request_complete(hdd_request);
1850 hdd_request_put(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001851}
1852
1853/**
1854 * __wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd
1855 * @wiphy: pointer to the wiphy
1856 * @wdev: pointer to the wdev
1857 * @data: The netlink data
1858 * @data_len: The length of the netlink data in bytes
1859 *
1860 * Return: 0 on success.
1861 */
1862static int __wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy,
1863 struct wireless_dev *wdev,
1864 const void *data,
1865 int data_len)
1866{
Jeff Johnson7106aba2017-08-28 11:49:07 -07001867 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001868 struct net_device *dev = wdev->netdev;
Jeff Johnson7a1688a2017-08-29 14:27:19 -07001869 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001870 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1];
1871 struct sir_dcc_update_ndl request;
1872 uint32_t channel_count;
1873 uint32_t ndl_channel_array_len;
1874 void *ndl_channel_array;
1875 uint32_t ndl_active_state_array_len;
1876 void *ndl_active_state_array;
Jeff Johnson7af334b2017-02-01 13:03:43 -08001877 int rc;
1878 QDF_STATUS status;
1879 void *cookie;
1880 struct hdd_request *hdd_request;
1881 struct hdd_dcc_update_ndl_priv *priv;
1882 static const struct hdd_request_params params = {
1883 .priv_size = sizeof(*priv),
1884 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1885 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001886
Jeff Johnson1f61b612016-02-12 16:28:33 -08001887 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001888
Jeff Johnson7af334b2017-02-01 13:03:43 -08001889 rc = wlan_hdd_validate_context(hdd_ctx);
1890 if (rc)
1891 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001892
Krunal Sonibe766b02016-03-10 13:00:44 -08001893 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001894 hdd_err("Device not in OCB mode!");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001895 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001896 }
1897
Jeff Johnson1b780e42017-10-31 14:11:45 -07001898 if (!wma_is_vdev_up(adapter->session_id)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001899 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001900 return -EINVAL;
1901 }
1902
1903 /* Parse the netlink message */
Dustin Brown4ea21db2018-01-05 14:13:17 -08001904 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX,
1905 data, data_len,
1906 qca_wlan_vendor_dcc_update_ndl)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001907 hdd_err("Invalid ATTR");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001908 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001909 }
1910
1911 /* Verify that the parameter is present */
1912 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] ||
1913 !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] ||
1914 !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001915 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001916 return -EINVAL;
1917 }
1918
1919 channel_count = nla_get_u32(
1920 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT]);
1921 ndl_channel_array_len = nla_len(
1922 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]);
1923 ndl_channel_array = nla_data(
1924 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]);
1925 ndl_active_state_array_len = nla_len(
1926 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]);
1927 ndl_active_state_array = nla_data(
1928 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]);
1929
Jeff Johnson7af334b2017-02-01 13:03:43 -08001930 hdd_request = hdd_request_alloc(&params);
1931 if (!hdd_request) {
1932 hdd_err("Request allocation failure");
1933 return -ENOMEM;
1934 }
1935 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001936
1937 /* Copy the parameters to the request structure. */
Jeff Johnson1b780e42017-10-31 14:11:45 -07001938 request.vdev_id = adapter->session_id;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001939 request.channel_count = channel_count;
1940 request.dcc_ndl_chan_list_len = ndl_channel_array_len;
1941 request.dcc_ndl_chan_list = ndl_channel_array;
1942 request.dcc_ndl_active_state_list_len = ndl_active_state_array_len;
1943 request.dcc_ndl_active_state_list = ndl_active_state_array;
1944
1945 /* Call the SME function */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001946 status = sme_dcc_update_ndl(hdd_ctx->hHal, cookie,
1947 hdd_dcc_update_ndl_callback,
1948 &request);
1949 if (QDF_IS_STATUS_ERROR(status)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001950 hdd_err("Error calling SME function.");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001951 rc = qdf_status_to_os_return(status);
1952 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001953 }
1954
1955 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001956 rc = hdd_request_wait_for_response(hdd_request);
1957 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001958 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001959 goto end;
1960 }
1961
Jeff Johnson7af334b2017-02-01 13:03:43 -08001962 priv = hdd_request_priv(hdd_request);
1963 rc = priv->status;
1964 if (rc) {
1965 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001966 goto end;
1967 }
1968
1969 /* fall through */
1970end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001971 hdd_request_put(hdd_request);
1972
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001973 return rc;
1974}
1975
1976/**
1977 * wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd
1978 * @wiphy: pointer to the wiphy
1979 * @wdev: pointer to the wdev
1980 * @data: The netlink data
1981 * @data_len: The length of the netlink data in bytes
1982 *
1983 * Return: 0 on success.
1984 */
1985int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy,
1986 struct wireless_dev *wdev,
1987 const void *data,
1988 int data_len)
1989{
1990 int ret;
1991
1992 cds_ssr_protect(__func__);
1993 ret = __wlan_hdd_cfg80211_dcc_update_ndl(wiphy, wdev,
1994 data, data_len);
1995 cds_ssr_unprotect(__func__);
1996
1997 return ret;
1998}
1999
2000/**
2001 * wlan_hdd_dcc_stats_event_callback() - Callback to get stats event
2002 * @context_ptr: request context
2003 * @response_ptr: response data
2004 */
2005static void wlan_hdd_dcc_stats_event_callback(void *context_ptr,
2006 void *response_ptr)
2007{
Jeff Johnson7106aba2017-08-28 11:49:07 -07002008 struct hdd_context *hdd_ctx = (struct hdd_context *)context_ptr;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002009 struct sir_dcc_get_stats_response *resp = response_ptr;
2010 struct sk_buff *vendor_event;
2011
2012 ENTER();
2013
2014 vendor_event =
2015 cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2016 NULL, sizeof(uint32_t) + resp->channel_stats_array_len +
2017 NLMSG_HDRLEN,
2018 QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX,
2019 GFP_KERNEL);
2020
2021 if (!vendor_event) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07002022 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002023 return;
2024 }
2025
2026 if (nla_put_u32(vendor_event,
2027 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT,
2028 resp->num_channels) ||
2029 nla_put(vendor_event,
2030 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY,
2031 resp->channel_stats_array_len,
2032 resp->channel_stats_array)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07002033 hdd_err("nla put failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002034 kfree_skb(vendor_event);
2035 return;
2036 }
2037
2038 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2039}
2040
2041/**
2042 * wlan_hdd_dcc_register_for_dcc_stats_event() - Register for dcc stats events
2043 * @hdd_ctx: hdd context
2044 */
Jeff Johnson7106aba2017-08-28 11:49:07 -07002045void wlan_hdd_dcc_register_for_dcc_stats_event(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002046{
2047 int rc;
2048
2049 rc = sme_register_for_dcc_stats_event(hdd_ctx->hHal, hdd_ctx,
Arun Khandavalli4b55da72016-07-19 19:55:01 +05302050 wlan_hdd_dcc_stats_event_callback);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002051 if (rc)
Jeff Johnson5f735d52016-07-06 15:14:45 -07002052 hdd_err("Register callback failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002053}