blob: 1e7325b2b67572691837ae09dfa1dc364b4544bb [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jeff Johnson441e1f72017-02-07 08:50:49 -08002 * Copyright (c) 2011-2017 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 */
63void hdd_set_dot11p_config(hdd_context_t *hdd_ctx)
64{
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
Dustin Browna30892e2016-10-12 17:28:36 -0700132 for (band_idx = 0; band_idx < 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 */
198static int hdd_ocb_validate_config(hdd_adapter_t *adapter,
199 struct sir_ocb_config *config)
200{
201 int i;
202 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
203
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 */
231static int hdd_ocb_register_sta(hdd_adapter_t *adapter)
232{
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};
235 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
236 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
237 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
Leo Changfdb45c32016-10-28 11:09:23 -0700242 qdf_status = cdp_peer_register_ocb_peer(soc, hdd_ctx->pcds_context,
243 adapter->macAddressCurrent.bytes,
244 &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,
260 (struct cdp_pdev *)pdev, adapter->sessionId),
261 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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800272 if (pHddStaCtx->conn_info.staId[0] != 0 &&
273 pHddStaCtx->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
277 pHddStaCtx->conn_info.staId[0] = peer_id;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530278 qdf_copy_macaddr(&pHddStaCtx->conn_info.peerMacAddress[0],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800279 &adapter->macAddressCurrent);
280
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)
368 hdd_err("Operation failed: %d", response->status);
369
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 */
386static int hdd_ocb_set_config_req(hdd_adapter_t *adapter,
387 struct sir_ocb_config *config)
388{
389 int rc;
Jeff Johnson7af334b2017-02-01 13:03:43 -0800390 QDF_STATUS status;
391 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
392 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
Jeff Johnson5f735d52016-07-06 15:14:45 -0700412 hdd_notice("Disabling queues");
Ravi Joshic3f5c8a2016-06-13 16:46:44 -0700413 wlan_hdd_netif_queue_control(adapter, WLAN_NETIF_TX_DISABLE_N_CARRIER,
414 WLAN_CONTROL_PATH);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800415
416 /* Call the SME API to set the config */
Jeff Johnson7af334b2017-02-01 13:03:43 -0800417 status = sme_ocb_set_config(hdd_ctx->hHal, cookie,
418 hdd_ocb_set_config_callback, config);
419 if (QDF_IS_STATUS_ERROR(status)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700420 hdd_err("Error calling SME function.");
Jeff Johnson7af334b2017-02-01 13:03:43 -0800421 rc = qdf_status_to_os_return(status);
422 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 }
424
425 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -0800426 rc = hdd_request_wait_for_response(hdd_request);
427 if (rc) {
428 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800429 goto end;
430 }
431
Jeff Johnson7af334b2017-02-01 13:03:43 -0800432 priv = hdd_request_priv(hdd_request);
433 rc = priv->status;
434 if (rc) {
435 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800436 goto end;
437 }
438
Jeff Johnson7af334b2017-02-01 13:03:43 -0800439 /*
440 * OCB set config command successful.
441 * Open the TX data path
442 */
443 if (!hdd_ocb_register_sta(adapter))
444 wlan_hdd_netif_queue_control(adapter,
445 WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
446 WLAN_CONTROL_PATH);
447
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800448 /* fall through */
449end:
Jeff Johnson7af334b2017-02-01 13:03:43 -0800450 hdd_request_put(hdd_request);
451
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800452 return rc;
453}
454
455/**
456 * __iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED
457 * ioctl
458 * @dev: Pointer to net_device structure
459 * @iw_request_info: IW Request Info
460 * @wrqu: IW Request Userspace Data Pointer
461 * @extra: IW Request Kernel Data Pointer
462 *
463 * Return: 0 on success
464 */
465static int __iw_set_dot11p_channel_sched(struct net_device *dev,
466 struct iw_request_info *info,
467 union iwreq_data *wrqu, char *extra)
468{
Jeff Johnson441e1f72017-02-07 08:50:49 -0800469 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800470 struct dot11p_channel_sched *sched;
Jeff Johnson441e1f72017-02-07 08:50:49 -0800471 hdd_context_t *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800472 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
473 struct sir_ocb_config *config = NULL;
474 uint8_t *mac_addr;
475 int i, j;
476 struct sir_ocb_config_channel *curr_chan;
477
Jeff Johnson6ee91ee2016-02-11 18:55:30 -0800478 ENTER_DEV(dev);
479
Jeff Johnson441e1f72017-02-07 08:50:49 -0800480 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
481 rc = wlan_hdd_validate_context(hdd_ctx);
482 if (0 != rc)
483 return rc;
484
485 rc = hdd_check_private_wext_control(hdd_ctx, info);
486 if (0 != rc)
487 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800488
Krunal Sonibe766b02016-03-10 13:00:44 -0800489 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700490 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800491 return -EINVAL;
492 }
493
494 sched = (struct dot11p_channel_sched *)extra;
495
496 /* Scheduled slots same as num channels for compatibility */
497 config = hdd_ocb_config_new(sched->num_channels, sched->num_channels,
498 0, 0);
499 if (config == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700500 hdd_err("Failed to allocate memory!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800501 return -ENOMEM;
502 }
503
504 /* Identify the vdev interface */
505 config->session_id = adapter->sessionId;
506
507 /* Release all the mac addresses used for OCB */
508 for (i = 0; i < adapter->ocb_mac_addr_count; i++) {
509 wlan_hdd_release_intf_addr(adapter->pHddCtx,
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800510 adapter->ocb_mac_address[i].bytes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800511 }
512 adapter->ocb_mac_addr_count = 0;
513
514 config->channel_count = 0;
515 for (i = 0; i < sched->num_channels; i++) {
516 if (0 == sched->channels[i].channel_freq)
517 continue;
518
519 curr_chan = &(config->channels[config->channel_count]);
520
521 curr_chan->chan_freq = sched->channels[i].channel_freq;
522 /*
523 * tx_power is divided by 2 because ocb_channel.tx_power is
524 * in half dB increments and sir_ocb_config_channel.max_pwr
525 * is in 1 dB increments.
526 */
527 curr_chan->max_pwr = sched->channels[i].tx_power / 2;
528 curr_chan->bandwidth = sched->channels[i].channel_bandwidth;
529 /* assume 10 as default if not provided */
530 if (curr_chan->bandwidth == 0)
531 curr_chan->bandwidth = 10;
532
533 /*
534 * Setup locally administered mac addresses for each channel.
535 * First channel uses the adapter's address.
536 */
537 if (i == 0) {
Anurag Chouhanc5548422016-02-24 18:33:27 +0530538 qdf_copy_macaddr(&curr_chan->mac_address,
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800539 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800540 } else {
541 mac_addr = wlan_hdd_get_intf_addr(adapter->pHddCtx);
542 if (mac_addr == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700543 hdd_err("Cannot obtain mac address");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800544 rc = -EINVAL;
545 goto fail;
546 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530547 qdf_mem_copy(config->channels[
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800548 config->channel_count].mac_address.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800549 mac_addr, sizeof(tSirMacAddr));
550 /* Save the mac address to release later */
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530551 qdf_mem_copy(adapter->ocb_mac_address[
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800552 adapter->ocb_mac_addr_count].bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530553 mac_addr, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800554 adapter->ocb_mac_addr_count++;
555 }
556
557 for (j = 0; j < MAX_NUM_AC; j++) {
558 curr_chan->qos_params[j].aifsn =
559 sched->channels[i].qos_params[j].aifsn;
560 curr_chan->qos_params[j].cwmin =
561 sched->channels[i].qos_params[j].cwmin;
562 curr_chan->qos_params[j].cwmax =
563 sched->channels[i].qos_params[j].cwmax;
564 }
565
566 config->channel_count++;
567 }
568
569 /*
570 * Scheduled slots same as num channels for compatibility with
571 * legacy use.
572 */
573 for (i = 0; i < sched->num_channels; i++) {
574 config->schedule[i].chan_freq = sched->channels[i].channel_freq;
575 config->schedule[i].guard_interval =
576 sched->channels[i].start_guard_interval;
577 config->schedule[i].total_duration =
578 sched->channels[i].duration;
579 }
580
581 rc = hdd_ocb_set_config_req(adapter, config);
582 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700583 hdd_err("Error while setting OCB config");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800584 goto fail;
585 }
586
587 rc = 0;
588
589fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530590 qdf_mem_free(config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800591 return rc;
592}
593
594/**
595 * iw_set_dot11p_channel_sched() - IOCTL interface for setting channel schedule
596 * @dev: Pointer to net_device structure
597 * @iw_request_info: IW Request Info
598 * @wrqu: IW Request Userspace Data Pointer
599 * @extra: IW Request Kernel Data Pointer
600 *
601 * Return: 0 on success.
602 */
603int iw_set_dot11p_channel_sched(struct net_device *dev,
604 struct iw_request_info *info,
605 union iwreq_data *wrqu, char *extra)
606{
607 int ret;
608
609 cds_ssr_protect(__func__);
610 ret = __iw_set_dot11p_channel_sched(dev, info, wrqu, extra);
611 cds_ssr_unprotect(__func__);
612
613 return ret;
614}
615
616static const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[
617 QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1] = {
618 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT] = {
619 .type = NLA_U32
620 },
621 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE] = {
622 .type = NLA_U32
623 },
624 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY] = {
625 .type = NLA_BINARY
626 },
627 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY] = {
628 .type = NLA_BINARY
629 },
630 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY] = {
631 .type = NLA_BINARY
632 },
633 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY] = {
634 .type = NLA_BINARY
635 },
636 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS] = {
637 .type = NLA_U32
638 },
639};
640
641static const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[
642 QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1] = {
643 [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE] = {
644 .type = NLA_BINARY, .len = SIZE_UTC_TIME
645 },
646 [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR] = {
647 .type = NLA_BINARY, .len = SIZE_UTC_TIME_ERROR
648 },
649};
650
651static const struct nla_policy qca_wlan_vendor_ocb_start_timing_advert_policy[
652 QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1] = {
653 [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ] = {
654 .type = NLA_U32
655 },
656 [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE] = {
657 .type = NLA_U32
658 },
659};
660
661static const struct nla_policy qca_wlan_vendor_ocb_stop_timing_advert_policy[
662 QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1] = {
663 [QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ] = {
664 .type = NLA_U32
665 },
666};
667
668static const struct nla_policy qca_wlan_vendor_ocb_get_tsf_timer_resp[] = {
669 [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH] = {
670 .type = NLA_U32
671 },
672 [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW] = {
673 .type = NLA_U32
674 },
675};
676
677static const struct nla_policy qca_wlan_vendor_dcc_get_stats[] = {
678 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] = {
679 .type = NLA_U32
680 },
681 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY] = {
682 .type = NLA_BINARY
683 },
684};
685
686static const struct nla_policy qca_wlan_vendor_dcc_get_stats_resp[] = {
687 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT] = {
688 .type = NLA_U32
689 },
690 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY] = {
691 .type = NLA_BINARY
692 },
693};
694
695static const struct nla_policy qca_wlan_vendor_dcc_clear_stats[] = {
696 [QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP] = {
697 .type = NLA_U32
698 },
699};
700
701static const struct nla_policy qca_wlan_vendor_dcc_update_ndl[
702 QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1] = {
703 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] = {
704 .type = NLA_U32
705 },
706 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] = {
707 .type = NLA_BINARY
708 },
709 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY] = {
710 .type = NLA_BINARY
711 },
712};
713
714/**
715 * struct wlan_hdd_ocb_config_channel
716 * @chan_freq: frequency of the channel
717 * @bandwidth: bandwidth of the channel, either 10 or 20 MHz
718 * @mac_address: MAC address assigned to this channel
719 * @qos_params: QoS parameters
720 * @max_pwr: maximum transmit power of the channel (1/2 dBm)
721 * @min_pwr: minimum transmit power of the channel (1/2 dBm)
722 */
723struct wlan_hdd_ocb_config_channel {
724 uint32_t chan_freq;
725 uint32_t bandwidth;
726 uint16_t flags;
727 uint8_t reserved[4];
728 struct sir_qos_params qos_params[MAX_NUM_AC];
729 uint32_t max_pwr;
730 uint32_t min_pwr;
731};
732
733static void wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel(
734 struct sir_ocb_config_channel *dest,
735 struct wlan_hdd_ocb_config_channel *src,
736 uint32_t channel_count)
737{
738 uint32_t i;
739
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530740 qdf_mem_zero(dest, channel_count * sizeof(*dest));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800741
742 for (i = 0; i < channel_count; i++) {
743 dest[i].chan_freq = src[i].chan_freq;
744 dest[i].bandwidth = src[i].bandwidth;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530745 qdf_mem_copy(dest[i].qos_params, src[i].qos_params,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800746 sizeof(dest[i].qos_params));
747 /*
748 * max_pwr and min_pwr are divided by 2 because
749 * wlan_hdd_ocb_config_channel.max_pwr and min_pwr
750 * are in 1/2 dB increments and
751 * sir_ocb_config_channel.max_pwr and min_pwr are in
752 * 1 dB increments.
753 */
754 dest[i].max_pwr = src[i].max_pwr / 2;
755 dest[i].min_pwr = (src[i].min_pwr + 1) / 2;
756 dest[i].flags = src[i].flags;
757 }
758}
759
760/**
761 * __wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command
762 * @wiphy: pointer to the wiphy
763 * @wdev: pointer to the wdev
764 * @data: The netlink data
765 * @data_len: The length of the netlink data in bytes
766 *
767 * Return: 0 on success.
768 */
769static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy,
770 struct wireless_dev *wdev,
771 const void *data,
772 int data_len)
773{
774 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
775 struct net_device *dev = wdev->netdev;
776 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
777 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1];
778 struct nlattr *channel_array;
779 struct nlattr *sched_array;
780 struct nlattr *ndl_chan_list;
781 uint32_t ndl_chan_list_len;
782 struct nlattr *ndl_active_state_list;
783 uint32_t ndl_active_state_list_len;
784 uint32_t flags = 0;
785 int i;
Jeff Johnson929ad032016-10-19 07:34:42 -0700786 uint32_t channel_count, schedule_size;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800787 struct sir_ocb_config *config;
788 int rc = -EINVAL;
789 uint8_t *mac_addr;
790
Jeff Johnson1f61b612016-02-12 16:28:33 -0800791 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800792
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530793 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800794 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800795
Krunal Sonibe766b02016-03-10 13:00:44 -0800796 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700797 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800798 return -EINVAL;
799 }
800
801 /* Parse the netlink message */
802 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX,
803 data,
804 data_len, qca_wlan_vendor_ocb_set_config_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700805 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806 return -EINVAL;
807 }
808
809 /* Get the number of channels in the schedule */
810 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700811 hdd_err("CHANNEL_COUNT is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800812 return -EINVAL;
813 }
814 channel_count = nla_get_u32(
815 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]);
816
817 /* Get the size of the channel schedule */
818 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700819 hdd_err("SCHEDULE_SIZE is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820 return -EINVAL;
821 }
822 schedule_size = nla_get_u32(
823 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]);
824
825 /* Get the ndl chan array and the ndl active state array. */
826 ndl_chan_list =
827 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY];
828 ndl_chan_list_len = (ndl_chan_list ? nla_len(ndl_chan_list) : 0);
829
830 ndl_active_state_list =
831 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY];
832 ndl_active_state_list_len = (ndl_active_state_list ?
833 nla_len(ndl_active_state_list) : 0);
834
835 /* Get the flags */
836 if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS])
837 flags = nla_get_u32(tb[
838 QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]);
839
840 config = hdd_ocb_config_new(channel_count, schedule_size,
841 ndl_chan_list_len,
842 ndl_active_state_list_len);
843 if (config == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700844 hdd_err("Failed to allocate memory!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800845 return -ENOMEM;
846 }
847
848 config->channel_count = channel_count;
849 config->schedule_size = schedule_size;
850 config->flags = flags;
851
852 /* Read the channel array */
853 channel_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY];
854 if (!channel_array) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700855 hdd_err("No channel present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800856 goto fail;
857 }
858 if (nla_len(channel_array) != channel_count *
859 sizeof(struct wlan_hdd_ocb_config_channel)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700860 hdd_err("CHANNEL_ARRAY is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800861 goto fail;
862 }
863 wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel(
864 config->channels, nla_data(channel_array), channel_count);
865
866 /* Identify the vdev interface */
867 config->session_id = adapter->sessionId;
868
869 /* Release all the mac addresses used for OCB */
870 for (i = 0; i < adapter->ocb_mac_addr_count; i++) {
871 wlan_hdd_release_intf_addr(adapter->pHddCtx,
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800872 adapter->ocb_mac_address[i].bytes);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873 }
874 adapter->ocb_mac_addr_count = 0;
875
876 /*
877 * Setup locally administered mac addresses for each channel.
878 * First channel uses the adapter's address.
879 */
880 for (i = 0; i < config->channel_count; i++) {
881 if (i == 0) {
Anurag Chouhanc5548422016-02-24 18:33:27 +0530882 qdf_copy_macaddr(&config->channels[i].mac_address,
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800883 &adapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800884 } else {
885 mac_addr = wlan_hdd_get_intf_addr(adapter->pHddCtx);
886 if (mac_addr == NULL) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700887 hdd_err("Cannot obtain mac address");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 goto fail;
889 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530890 qdf_mem_copy(config->channels[i].mac_address.bytes,
Anurag Chouhan6d760662016-02-20 16:05:43 +0530891 mac_addr, QDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800892 /* Save the mac address to release later */
Anurag Chouhanc5548422016-02-24 18:33:27 +0530893 qdf_copy_macaddr(&adapter->ocb_mac_address[
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800894 adapter->ocb_mac_addr_count],
Srinivas Girigowda117e7fb2015-11-16 12:33:45 -0800895 &config->channels[i].mac_address);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800896 adapter->ocb_mac_addr_count++;
897 }
898 }
899
900 /* Read the schedule array */
901 sched_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY];
902 if (!sched_array) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700903 hdd_err("No channel present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800904 goto fail;
905 }
906 if (nla_len(sched_array) != schedule_size * sizeof(*config->schedule)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700907 hdd_err("SCHEDULE_ARRAY is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800908 goto fail;
909 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530910 qdf_mem_copy(config->schedule, nla_data(sched_array),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800911 nla_len(sched_array));
912
913 /* Copy the NDL chan array */
914 if (ndl_chan_list_len) {
915 config->dcc_ndl_chan_list_len = ndl_chan_list_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530916 qdf_mem_copy(config->dcc_ndl_chan_list, nla_data(ndl_chan_list),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 nla_len(ndl_chan_list));
918 }
919
920 /* Copy the NDL active state array */
921 if (ndl_active_state_list_len) {
922 config->dcc_ndl_active_state_list_len =
923 ndl_active_state_list_len;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530924 qdf_mem_copy(config->dcc_ndl_active_state_list,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800925 nla_data(ndl_active_state_list),
926 nla_len(ndl_active_state_list));
927 }
928
929 rc = hdd_ocb_set_config_req(adapter, config);
930 if (rc)
Jeff Johnson5f735d52016-07-06 15:14:45 -0700931 hdd_err("Error while setting OCB config: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800932
933fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530934 qdf_mem_free(config);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800935 return rc;
936}
937
938/**
939 * wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command
940 * @wiphy: pointer to the wiphy
941 * @wdev: pointer to the wdev
942 * @data: The netlink data
943 * @data_len: The length of the netlink data in bytes
944 *
945 * Return: 0 on success.
946 */
947int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy,
948 struct wireless_dev *wdev,
949 const void *data,
950 int data_len)
951{
952 int ret;
953
954 cds_ssr_protect(__func__);
955 ret = __wlan_hdd_cfg80211_ocb_set_config(wiphy, wdev, data, data_len);
956 cds_ssr_unprotect(__func__);
957
958 return ret;
959}
960
961/**
962 * __wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for set UTC time command
963 * @wiphy: pointer to the wiphy
964 * @wdev: pointer to the wdev
965 * @data: The netlink data
966 * @data_len: The length of the netlink data in bytes
967 *
968 * Return: 0 on success.
969 */
970static int __wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy,
971 struct wireless_dev *wdev,
972 const void *data,
973 int data_len)
974{
975 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
976 struct net_device *dev = wdev->netdev;
977 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
978 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1];
979 struct nlattr *utc_attr;
980 struct nlattr *time_error_attr;
981 struct sir_ocb_utc *utc;
982 int rc = -EINVAL;
983
Jeff Johnson1f61b612016-02-12 16:28:33 -0800984 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800985
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530986 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800987 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800988
Krunal Sonibe766b02016-03-10 13:00:44 -0800989 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700990 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800991 return -EINVAL;
992 }
993
994 if (!wma_is_vdev_up(adapter->sessionId)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -0700995 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800996 return -EINVAL;
997 }
998
999 /* Parse the netlink message */
1000 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX,
1001 data,
1002 data_len, qca_wlan_vendor_ocb_set_utc_time_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001003 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001004 return -EINVAL;
1005 }
1006
1007 /* Read the UTC time */
1008 utc_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE];
1009 if (!utc_attr) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001010 hdd_err("UTC_TIME is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001011 return -EINVAL;
1012 }
1013 if (nla_len(utc_attr) != SIZE_UTC_TIME) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001014 hdd_err("UTC_TIME is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001015 return -EINVAL;
1016 }
1017
1018 /* Read the time error */
1019 time_error_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR];
1020 if (!time_error_attr) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001021 hdd_err("UTC_TIME is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001022 return -EINVAL;
1023 }
1024 if (nla_len(time_error_attr) != SIZE_UTC_TIME_ERROR) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001025 hdd_err("UTC_TIME is not the correct size");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001026 return -EINVAL;
1027 }
1028
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301029 utc = qdf_mem_malloc(sizeof(*utc));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001030 if (!utc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001031 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001032 return -ENOMEM;
1033 }
1034 utc->vdev_id = adapter->sessionId;
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301035 qdf_mem_copy(utc->utc_time, nla_data(utc_attr), SIZE_UTC_TIME);
1036 qdf_mem_copy(utc->time_error, nla_data(time_error_attr),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001037 SIZE_UTC_TIME_ERROR);
1038
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301039 if (sme_ocb_set_utc_time(hdd_ctx->hHal, utc) != QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001040 hdd_err("Error while setting UTC time");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001041 rc = -EINVAL;
1042 } else {
1043 rc = 0;
1044 }
1045
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301046 qdf_mem_free(utc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001047 return rc;
1048}
1049
1050/**
1051 * wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for the set UTC time command
1052 * @wiphy: pointer to the wiphy
1053 * @wdev: pointer to the wdev
1054 * @data: The netlink data
1055 * @data_len: The length of the netlink data in bytes
1056 *
1057 * Return: 0 on success.
1058 */
1059int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy,
1060 struct wireless_dev *wdev,
1061 const void *data,
1062 int data_len)
1063{
1064 int ret;
1065
1066 cds_ssr_protect(__func__);
1067 ret = __wlan_hdd_cfg80211_ocb_set_utc_time(wiphy, wdev, data, data_len);
1068 cds_ssr_unprotect(__func__);
1069
1070 return ret;
1071}
1072
1073/**
1074 * __wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for start TA cmd
1075 * @wiphy: pointer to the wiphy
1076 * @wdev: pointer to the wdev
1077 * @data: The netlink data
1078 * @data_len: The length of the netlink data in bytes
1079 *
1080 * Return: 0 on success.
1081 */
1082static int
1083__wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy,
1084 struct wireless_dev *wdev,
1085 const void *data,
1086 int data_len)
1087{
1088 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1089 struct net_device *dev = wdev->netdev;
1090 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001091 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1];
1092 struct sir_ocb_timing_advert *timing_advert;
1093 int rc = -EINVAL;
1094
Jeff Johnson1f61b612016-02-12 16:28:33 -08001095 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001096
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301097 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001098 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001099
Krunal Sonibe766b02016-03-10 13:00:44 -08001100 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001101 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001102 return -EINVAL;
1103 }
1104
1105 if (!wma_is_vdev_up(adapter->sessionId)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001106 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001107 return -EINVAL;
1108 }
1109
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301110 timing_advert = qdf_mem_malloc(sizeof(*timing_advert));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001111 if (!timing_advert) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001112 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001113 return -ENOMEM;
1114 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001115 timing_advert->vdev_id = adapter->sessionId;
1116
1117 /* Parse the netlink message */
1118 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX,
1119 data,
1120 data_len,
1121 qca_wlan_vendor_ocb_start_timing_advert_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001122 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001123 goto fail;
1124 }
1125
1126 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001127 hdd_err("CHANNEL_FREQ is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001128 goto fail;
1129 }
1130 timing_advert->chan_freq = nla_get_u32(
1131 tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]);
1132
1133 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001134 hdd_err("REPEAT_RATE is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001135 goto fail;
1136 }
1137 timing_advert->repeat_rate = nla_get_u32(
1138 tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]);
1139
1140 timing_advert->template_length =
Naveen Rawatb4d37622015-11-13 16:15:25 -08001141 sme_ocb_gen_timing_advert_frame(hdd_ctx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001142 *(tSirMacAddr *)&adapter->macAddressCurrent.bytes,
1143 &timing_advert->template_value,
1144 &timing_advert->timestamp_offset,
1145 &timing_advert->time_value_offset);
1146 if (timing_advert->template_length <= 0) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001147 hdd_err("Error while generating the TA frame");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148 goto fail;
1149 }
1150
1151 if (sme_ocb_start_timing_advert(hdd_ctx->hHal, timing_advert) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301152 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001153 hdd_err("Error while starting timing advert");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001154 rc = -EINVAL;
1155 } else {
1156 rc = 0;
1157 }
1158
1159fail:
1160 if (timing_advert->template_value)
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301161 qdf_mem_free(timing_advert->template_value);
1162 qdf_mem_free(timing_advert);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001163 return rc;
1164}
1165
1166/**
1167 * wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for the start TA cmd
1168 * @wiphy: pointer to the wiphy
1169 * @wdev: pointer to the wdev
1170 * @data: The netlink data
1171 * @data_len: The length of the netlink data in bytes
1172 *
1173 * Return: 0 on success.
1174 */
1175int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy,
1176 struct wireless_dev *wdev,
1177 const void *data,
1178 int data_len)
1179{
1180 int ret;
1181
1182 cds_ssr_protect(__func__);
1183 ret = __wlan_hdd_cfg80211_ocb_start_timing_advert(wiphy, wdev,
1184 data, data_len);
1185 cds_ssr_unprotect(__func__);
1186
1187 return ret;
1188}
1189
1190/**
1191 * __wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd
1192 * @wiphy: pointer to the wiphy
1193 * @wdev: pointer to the wdev
1194 * @data: The netlink data
1195 * @data_len: The length of the netlink data in bytes
1196 *
1197 * Return: 0 on success.
1198 */
1199static int
1200__wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy,
1201 struct wireless_dev *wdev,
1202 const void *data,
1203 int data_len)
1204{
1205 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1206 struct net_device *dev = wdev->netdev;
1207 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1208 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1];
1209 struct sir_ocb_timing_advert *timing_advert;
1210 int rc = -EINVAL;
1211
Jeff Johnson1f61b612016-02-12 16:28:33 -08001212 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001213
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301214 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001215 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001216
Krunal Sonibe766b02016-03-10 13:00:44 -08001217 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001218 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001219 return -EINVAL;
1220 }
1221
1222 if (!wma_is_vdev_up(adapter->sessionId)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001223 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001224 return -EINVAL;
1225 }
1226
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301227 timing_advert = qdf_mem_malloc(sizeof(*timing_advert));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001228 if (!timing_advert) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001229 hdd_err("qdf_mem_malloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001230 return -ENOMEM;
1231 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001232 timing_advert->vdev_id = adapter->sessionId;
1233
1234 /* Parse the netlink message */
1235 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX,
1236 data,
1237 data_len,
1238 qca_wlan_vendor_ocb_stop_timing_advert_policy)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001239 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001240 goto fail;
1241 }
1242
1243 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001244 hdd_err("CHANNEL_FREQ is not present");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001245 goto fail;
1246 }
1247 timing_advert->chan_freq = nla_get_u32(
1248 tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]);
1249
1250 if (sme_ocb_stop_timing_advert(hdd_ctx->hHal, timing_advert) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301251 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001252 hdd_err("Error while stopping timing advert");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001253 rc = -EINVAL;
1254 } else {
1255 rc = 0;
1256 }
1257
1258fail:
Anurag Chouhan600c3a02016-03-01 10:33:54 +05301259 qdf_mem_free(timing_advert);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001260 return rc;
1261}
1262
1263/**
1264 * wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd
1265 * @wiphy: pointer to the wiphy
1266 * @wdev: pointer to the wdev
1267 * @data: The netlink data
1268 * @data_len: The length of the netlink data in bytes
1269 *
1270 * Return: 0 on success.
1271 */
1272int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy,
1273 struct wireless_dev *wdev,
1274 const void *data,
1275 int data_len)
1276{
1277 int ret;
1278
1279 cds_ssr_protect(__func__);
1280 ret = __wlan_hdd_cfg80211_ocb_stop_timing_advert(wiphy, wdev,
1281 data, data_len);
1282 cds_ssr_unprotect(__func__);
1283
1284 return ret;
1285}
1286
Jeff Johnson7af334b2017-02-01 13:03:43 -08001287struct hdd_ocb_get_tsf_timer_priv {
1288 struct sir_ocb_get_tsf_timer_response response;
1289 int status;
1290};
1291
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001292/**
1293 * hdd_ocb_get_tsf_timer_callback() - Callback to get TSF command
1294 * @context_ptr: request context
1295 * @response_ptr: response data
1296 */
1297static void hdd_ocb_get_tsf_timer_callback(void *context_ptr,
1298 void *response_ptr)
1299{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001300 struct hdd_request *hdd_request;
1301 struct hdd_ocb_get_tsf_timer_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001302 struct sir_ocb_get_tsf_timer_response *response = response_ptr;
1303
Jeff Johnson7af334b2017-02-01 13:03:43 -08001304 hdd_request = hdd_request_get(context_ptr);
1305 if (!hdd_request) {
1306 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001307 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001308 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001309
1310 if (response) {
1311 priv->response = *response;
1312 priv->status = 0;
1313 } else {
1314 priv->status = -EINVAL;
1315 }
1316 hdd_request_complete(hdd_request);
1317 hdd_request_put(hdd_request);
1318}
1319
1320static int
1321hdd_ocb_get_tsf_timer_reply(struct wiphy *wiphy,
1322 struct sir_ocb_get_tsf_timer_response *response)
1323{
1324 uint32_t nl_buf_len;
1325 struct sk_buff *nl_resp;
1326 int rc;
1327
1328 /* Allocate the buffer for the response. */
1329 nl_buf_len = NLMSG_HDRLEN;
1330 nl_buf_len += 2 * (NLA_HDRLEN + sizeof(uint32_t));
1331 nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
1332 if (!nl_resp) {
1333 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
1334 return -ENOMEM;
1335 }
1336
1337 /* Populate the response. */
1338 rc = nla_put_u32(nl_resp,
1339 QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH,
1340 response->timer_high);
1341 if (rc)
1342 goto end;
1343 rc = nla_put_u32(nl_resp,
1344 QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW,
1345 response->timer_low);
1346 if (rc)
1347 goto end;
1348
1349 /* Send the response. */
1350 rc = cfg80211_vendor_cmd_reply(nl_resp);
1351 nl_resp = NULL;
1352 if (rc) {
1353 hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc);
1354 goto end;
1355 }
1356end:
1357 if (nl_resp)
1358 kfree_skb(nl_resp);
1359
1360 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001361}
1362
1363/**
1364 * __wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd
1365 * @wiphy: pointer to the wiphy
1366 * @wdev: pointer to the wdev
1367 * @data: The netlink data
1368 * @data_len: The length of the netlink data in bytes
1369 *
1370 * Return: 0 on success.
1371 */
1372static int
1373__wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy,
1374 struct wireless_dev *wdev,
1375 const void *data,
1376 int data_len)
1377{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001378 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1379 struct net_device *dev = wdev->netdev;
1380 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
Jeff Johnson7af334b2017-02-01 13:03:43 -08001381 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001382 struct sir_ocb_get_tsf_timer request = {0};
Jeff Johnson7af334b2017-02-01 13:03:43 -08001383 QDF_STATUS status;
1384 void *cookie;
1385 struct hdd_request *hdd_request;
1386 struct hdd_ocb_get_tsf_timer_priv *priv;
1387 static const struct hdd_request_params params = {
1388 .priv_size = sizeof(*priv),
1389 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1390 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001391
Jeff Johnson1f61b612016-02-12 16:28:33 -08001392 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001393
Jeff Johnson7af334b2017-02-01 13:03:43 -08001394 rc = wlan_hdd_validate_context(hdd_ctx);
1395 if (rc)
1396 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001397
Krunal Sonibe766b02016-03-10 13:00:44 -08001398 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001399 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001400 return -EINVAL;
1401 }
1402
1403 if (!wma_is_vdev_up(adapter->sessionId)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001404 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001405 return -EINVAL;
1406 }
1407
Jeff Johnson7af334b2017-02-01 13:03:43 -08001408 hdd_request = hdd_request_alloc(&params);
1409 if (!hdd_request) {
1410 hdd_err("Request allocation failure");
1411 return -ENOMEM;
1412 }
1413 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001414
1415 request.vdev_id = adapter->sessionId;
1416 /* Call the SME function */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001417 status = sme_ocb_get_tsf_timer(hdd_ctx->hHal, cookie,
1418 hdd_ocb_get_tsf_timer_callback,
1419 &request);
1420 if (QDF_IS_STATUS_ERROR(status)) {
1421 hdd_err("Error calling SME function.");
1422 rc = qdf_status_to_os_return(status);
1423 goto end;
1424 }
1425
1426 rc = hdd_request_wait_for_response(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001427 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001428 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001429 goto end;
1430 }
1431
Jeff Johnson7af334b2017-02-01 13:03:43 -08001432 priv = hdd_request_priv(hdd_request);
1433 rc = priv->status;
1434 if (rc) {
1435 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001436 goto end;
1437 }
1438
Jeff Johnson5f735d52016-07-06 15:14:45 -07001439 hdd_err("Got TSF timer response, high=%d, low=%d",
Jeff Johnson7af334b2017-02-01 13:03:43 -08001440 priv->response.timer_high,
1441 priv->response.timer_low);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001442
1443 /* Send the response. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001444 rc = hdd_ocb_get_tsf_timer_reply(wiphy, &priv->response);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001445 if (rc) {
Jeff Johnson7af334b2017-02-01 13:03:43 -08001446 hdd_err("hdd_ocb_get_tsf_timer_reply failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001447 goto end;
1448 }
1449
Jeff Johnson7af334b2017-02-01 13:03:43 -08001450 /* fall through */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001451end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001452 hdd_request_put(hdd_request);
1453
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001454 return rc;
1455}
1456
1457/**
1458 * wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd
1459 * @wiphy: pointer to the wiphy
1460 * @wdev: pointer to the wdev
1461 * @data: The netlink data
1462 * @data_len: The length of the netlink data in bytes
1463 *
1464 * Return: 0 on success.
1465 */
1466int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy,
1467 struct wireless_dev *wdev,
1468 const void *data,
1469 int data_len)
1470{
1471 int ret;
1472
1473 cds_ssr_protect(__func__);
1474 ret = __wlan_hdd_cfg80211_ocb_get_tsf_timer(wiphy, wdev,
1475 data, data_len);
1476 cds_ssr_unprotect(__func__);
1477
1478 return ret;
1479}
1480
Jeff Johnson7af334b2017-02-01 13:03:43 -08001481struct hdd_dcc_stats_priv {
1482 struct sir_dcc_get_stats_response *response;
1483 int status;
1484};
1485
1486static void hdd_dcc_get_stats_dealloc(void *context_ptr)
1487{
1488 struct hdd_dcc_stats_priv *priv = context_ptr;
1489
1490 qdf_mem_free(priv->response);
1491 priv->response = NULL;
1492}
1493
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001494/**
1495 * hdd_dcc_get_stats_callback() - Callback to get stats command
1496 * @context_ptr: request context
1497 * @response_ptr: response data
1498 */
1499static void hdd_dcc_get_stats_callback(void *context_ptr, void *response_ptr)
1500{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001501 struct hdd_request *hdd_request;
1502 struct hdd_dcc_stats_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001503 struct sir_dcc_get_stats_response *response = response_ptr;
1504 struct sir_dcc_get_stats_response *hdd_resp;
1505
Jeff Johnson7af334b2017-02-01 13:03:43 -08001506 hdd_request = hdd_request_get(context_ptr);
1507 if (!hdd_request) {
1508 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001509 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001510 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001511
1512 priv = hdd_request_priv(hdd_request);
1513 if (!response) {
1514 priv->status = -EINVAL;
1515 goto end;
1516 }
1517
1518 priv->response = qdf_mem_malloc(sizeof(*response) +
1519 response->channel_stats_array_len);
1520 if (!priv->response) {
1521 priv->status = -ENOMEM;
1522 goto end;
1523 }
1524
1525 hdd_resp = priv->response;
1526 *hdd_resp = *response;
1527 hdd_resp->channel_stats_array = (void *)hdd_resp + sizeof(*hdd_resp);
1528 qdf_mem_copy(hdd_resp->channel_stats_array,
1529 response->channel_stats_array,
1530 response->channel_stats_array_len);
1531 priv->status = 0;
1532
1533end:
1534 hdd_request_complete(hdd_request);
1535 hdd_request_put(hdd_request);
1536}
1537
1538static int
1539hdd_dcc_get_stats_send_reply(struct wiphy *wiphy,
1540 struct sir_dcc_get_stats_response *response)
1541{
1542 uint32_t nl_buf_len;
1543 struct sk_buff *nl_resp;
1544 int rc;
1545
1546 /* Allocate the buffer for the response. */
1547 nl_buf_len = NLMSG_HDRLEN;
1548 nl_buf_len += NLA_HDRLEN + sizeof(uint32_t);
1549 nl_buf_len += NLA_HDRLEN + response->channel_stats_array_len;
1550 nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
1551 if (!nl_resp) {
1552 hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
1553 return -ENOMEM;
1554 }
1555
1556 /* Populate the response. */
1557 rc = nla_put_u32(nl_resp,
1558 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT,
1559 response->num_channels);
1560 if (rc)
1561 goto end;
1562 rc = nla_put(nl_resp,
1563 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY,
1564 response->channel_stats_array_len,
1565 response->channel_stats_array);
1566 if (rc)
1567 goto end;
1568
1569 /* Send the response. */
1570 rc = cfg80211_vendor_cmd_reply(nl_resp);
1571 nl_resp = NULL;
1572 if (rc) {
1573 hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc);
1574 goto end;
1575 }
1576end:
1577 if (nl_resp)
1578 kfree_skb(nl_resp);
1579
1580 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001581}
1582
1583/**
1584 * __wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats
1585 * @wiphy: pointer to the wiphy
1586 * @wdev: pointer to the wdev
1587 * @data: The netlink data
1588 * @data_len: The length of the netlink data in bytes
1589 *
1590 * Return: 0 on success.
1591 */
1592static int __wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy,
1593 struct wireless_dev *wdev,
1594 const void *data,
1595 int data_len)
1596{
1597 uint32_t channel_count = 0;
1598 uint32_t request_array_len = 0;
1599 void *request_array = 0;
1600 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1601 struct net_device *dev = wdev->netdev;
1602 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1603 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX + 1];
Jeff Johnson7af334b2017-02-01 13:03:43 -08001604 int rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001605 struct sir_dcc_get_stats request = {0};
Jeff Johnson7af334b2017-02-01 13:03:43 -08001606 QDF_STATUS status;
1607 void *cookie;
1608 struct hdd_request *hdd_request;
1609 struct hdd_dcc_stats_priv *priv;
1610 static const struct hdd_request_params params = {
1611 .priv_size = sizeof(*priv),
1612 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1613 .dealloc = hdd_dcc_get_stats_dealloc,
1614 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001615
Jeff Johnson1f61b612016-02-12 16:28:33 -08001616 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001617
Jeff Johnson7af334b2017-02-01 13:03:43 -08001618 rc = wlan_hdd_validate_context(hdd_ctx);
1619 if (rc)
1620 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001621
Krunal Sonibe766b02016-03-10 13:00:44 -08001622 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001623 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001624 return -EINVAL;
1625 }
1626
1627 if (!wma_is_vdev_up(adapter->sessionId)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001628 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001629 return -EINVAL;
1630 }
1631
1632 /* Parse the netlink message */
1633 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX,
1634 data,
1635 data_len,
1636 qca_wlan_vendor_dcc_get_stats)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001637 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001638 return -EINVAL;
1639 }
1640
1641 /* Validate all the parameters are present */
1642 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] ||
1643 !tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001644 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001645 return -EINVAL;
1646 }
1647
1648 channel_count = nla_get_u32(
1649 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT]);
1650 request_array_len = nla_len(
1651 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]);
1652 request_array = nla_data(
1653 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]);
1654
Jeff Johnson7af334b2017-02-01 13:03:43 -08001655 hdd_request = hdd_request_alloc(&params);
1656 if (!hdd_request) {
1657 hdd_err("Request allocation failure");
1658 return -ENOMEM;
1659 }
1660 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001661
1662 request.vdev_id = adapter->sessionId;
1663 request.channel_count = channel_count;
1664 request.request_array_len = request_array_len;
1665 request.request_array = request_array;
1666
1667 /* Call the SME function. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001668 status = sme_dcc_get_stats(hdd_ctx->hHal, cookie,
1669 hdd_dcc_get_stats_callback,
1670 &request);
1671 if (QDF_IS_STATUS_ERROR(status)) {
1672 hdd_err("Error calling SME function.");
1673 rc = qdf_status_to_os_return(status);
1674 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001675 }
1676
1677 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001678 rc = hdd_request_wait_for_response(hdd_request);
1679 if (rc) {
1680 hdd_err("Operation timed out");
1681 goto end;
1682 }
1683
1684 priv = hdd_request_priv(hdd_request);
1685 rc = priv->status;
1686 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001687 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001688 goto end;
1689 }
1690
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001691 /* Send the response. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001692 rc = hdd_dcc_get_stats_send_reply(wiphy, priv->response);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001693 if (rc) {
Jeff Johnson7af334b2017-02-01 13:03:43 -08001694 hdd_err("hdd_dcc_get_stats_send_reply failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001695 goto end;
1696 }
1697
1698 /* fall through */
1699end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001700 hdd_request_put(hdd_request);
1701
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001702 return rc;
1703}
1704
1705/**
1706 * wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats
1707 * @wiphy: pointer to the wiphy
1708 * @wdev: pointer to the wdev
1709 * @data: The netlink data
1710 * @data_len: The length of the netlink data in bytes
1711 *
1712 * Return: 0 on success.
1713 */
1714int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy,
1715 struct wireless_dev *wdev,
1716 const void *data,
1717 int data_len)
1718{
1719 int ret;
1720
1721 cds_ssr_protect(__func__);
1722 ret = __wlan_hdd_cfg80211_dcc_get_stats(wiphy, wdev,
1723 data, data_len);
1724 cds_ssr_unprotect(__func__);
1725
1726 return ret;
1727}
1728
1729/**
1730 * __wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd
1731 * @wiphy: pointer to the wiphy
1732 * @wdev: pointer to the wdev
1733 * @data: The netlink data
1734 * @data_len: The length of the netlink data in bytes
1735 *
1736 * Return: 0 on success.
1737 */
1738static int __wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy,
1739 struct wireless_dev *wdev,
1740 const void *data,
1741 int data_len)
1742{
1743 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1744 struct net_device *dev = wdev->netdev;
1745 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1746 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX + 1];
1747
Jeff Johnson1f61b612016-02-12 16:28:33 -08001748 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001749
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301750 if (wlan_hdd_validate_context(hdd_ctx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001751 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001752
Krunal Sonibe766b02016-03-10 13:00:44 -08001753 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001754 hdd_err("Device not in OCB mode!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001755 return -EINVAL;
1756 }
1757
1758 if (!wma_is_vdev_up(adapter->sessionId)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001759 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001760 return -EINVAL;
1761 }
1762
1763 /* Parse the netlink message */
1764 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX,
1765 data,
1766 data_len,
1767 qca_wlan_vendor_dcc_clear_stats)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001768 hdd_err("Invalid ATTR");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001769 return -EINVAL;
1770 }
1771
1772 /* Verify that the parameter is present */
1773 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001774 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001775 return -EINVAL;
1776 }
1777
1778 /* Call the SME function */
1779 if (sme_dcc_clear_stats(hdd_ctx->hHal, adapter->sessionId,
1780 nla_get_u32(
1781 tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP])) !=
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301782 QDF_STATUS_SUCCESS) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001783 hdd_err("Error calling SME function.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001784 return -EINVAL;
1785 }
1786
1787 return 0;
1788}
1789
1790/**
1791 * wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd
1792 * @wiphy: pointer to the wiphy
1793 * @wdev: pointer to the wdev
1794 * @data: The netlink data
1795 * @data_len: The length of the netlink data in bytes
1796 *
1797 * Return: 0 on success.
1798 */
1799int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy,
1800 struct wireless_dev *wdev,
1801 const void *data,
1802 int data_len)
1803{
1804 int ret;
1805
1806 cds_ssr_protect(__func__);
1807 ret = __wlan_hdd_cfg80211_dcc_clear_stats(wiphy, wdev,
1808 data, data_len);
1809 cds_ssr_unprotect(__func__);
1810
1811 return ret;
1812}
1813
Jeff Johnson7af334b2017-02-01 13:03:43 -08001814struct hdd_dcc_update_ndl_priv {
1815 int status;
1816};
1817
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001818/**
1819 * hdd_dcc_update_ndl_callback() - Callback to update NDL command
1820 * @context_ptr: request context
1821 * @response_ptr: response data
1822 */
1823static void hdd_dcc_update_ndl_callback(void *context_ptr, void *response_ptr)
1824{
Jeff Johnson7af334b2017-02-01 13:03:43 -08001825 struct hdd_request *hdd_request;
1826 struct hdd_dcc_update_ndl_priv *priv;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001827 struct sir_dcc_update_ndl_response *response = response_ptr;
1828
Jeff Johnson7af334b2017-02-01 13:03:43 -08001829 hdd_request = hdd_request_get(context_ptr);
1830 if (!hdd_request) {
1831 hdd_err("Obsolete request");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001832 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001833 }
Jeff Johnson7af334b2017-02-01 13:03:43 -08001834 priv = hdd_request_priv(hdd_request);
1835 if (response && (0 == response->status)) {
1836 priv->status = 0;
1837 } else {
1838 priv->status = -EINVAL;
1839 }
1840 hdd_request_complete(hdd_request);
1841 hdd_request_put(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001842}
1843
1844/**
1845 * __wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd
1846 * @wiphy: pointer to the wiphy
1847 * @wdev: pointer to the wdev
1848 * @data: The netlink data
1849 * @data_len: The length of the netlink data in bytes
1850 *
1851 * Return: 0 on success.
1852 */
1853static int __wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy,
1854 struct wireless_dev *wdev,
1855 const void *data,
1856 int data_len)
1857{
1858 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1859 struct net_device *dev = wdev->netdev;
1860 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1861 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1];
1862 struct sir_dcc_update_ndl request;
1863 uint32_t channel_count;
1864 uint32_t ndl_channel_array_len;
1865 void *ndl_channel_array;
1866 uint32_t ndl_active_state_array_len;
1867 void *ndl_active_state_array;
Jeff Johnson7af334b2017-02-01 13:03:43 -08001868 int rc;
1869 QDF_STATUS status;
1870 void *cookie;
1871 struct hdd_request *hdd_request;
1872 struct hdd_dcc_update_ndl_priv *priv;
1873 static const struct hdd_request_params params = {
1874 .priv_size = sizeof(*priv),
1875 .timeout_ms = WLAN_WAIT_TIME_OCB_CMD,
1876 };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001877
Jeff Johnson1f61b612016-02-12 16:28:33 -08001878 ENTER_DEV(dev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001879
Jeff Johnson7af334b2017-02-01 13:03:43 -08001880 rc = wlan_hdd_validate_context(hdd_ctx);
1881 if (rc)
1882 return rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001883
Krunal Sonibe766b02016-03-10 13:00:44 -08001884 if (adapter->device_mode != QDF_OCB_MODE) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001885 hdd_err("Device not in OCB mode!");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001886 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001887 }
1888
1889 if (!wma_is_vdev_up(adapter->sessionId)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001890 hdd_err("The device has not been started");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001891 return -EINVAL;
1892 }
1893
1894 /* Parse the netlink message */
1895 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX,
1896 data,
1897 data_len,
1898 qca_wlan_vendor_dcc_update_ndl)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001899 hdd_err("Invalid ATTR");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001900 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001901 }
1902
1903 /* Verify that the parameter is present */
1904 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] ||
1905 !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] ||
1906 !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001907 hdd_err("Parameters are not present.");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001908 return -EINVAL;
1909 }
1910
1911 channel_count = nla_get_u32(
1912 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT]);
1913 ndl_channel_array_len = nla_len(
1914 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]);
1915 ndl_channel_array = nla_data(
1916 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]);
1917 ndl_active_state_array_len = nla_len(
1918 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]);
1919 ndl_active_state_array = nla_data(
1920 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]);
1921
Jeff Johnson7af334b2017-02-01 13:03:43 -08001922 hdd_request = hdd_request_alloc(&params);
1923 if (!hdd_request) {
1924 hdd_err("Request allocation failure");
1925 return -ENOMEM;
1926 }
1927 cookie = hdd_request_cookie(hdd_request);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001928
1929 /* Copy the parameters to the request structure. */
1930 request.vdev_id = adapter->sessionId;
1931 request.channel_count = channel_count;
1932 request.dcc_ndl_chan_list_len = ndl_channel_array_len;
1933 request.dcc_ndl_chan_list = ndl_channel_array;
1934 request.dcc_ndl_active_state_list_len = ndl_active_state_array_len;
1935 request.dcc_ndl_active_state_list = ndl_active_state_array;
1936
1937 /* Call the SME function */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001938 status = sme_dcc_update_ndl(hdd_ctx->hHal, cookie,
1939 hdd_dcc_update_ndl_callback,
1940 &request);
1941 if (QDF_IS_STATUS_ERROR(status)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001942 hdd_err("Error calling SME function.");
Jeff Johnson7af334b2017-02-01 13:03:43 -08001943 rc = qdf_status_to_os_return(status);
1944 goto end;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001945 }
1946
1947 /* Wait for the function to complete. */
Jeff Johnson7af334b2017-02-01 13:03:43 -08001948 rc = hdd_request_wait_for_response(hdd_request);
1949 if (rc) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07001950 hdd_err("Operation timed out");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001951 goto end;
1952 }
1953
Jeff Johnson7af334b2017-02-01 13:03:43 -08001954 priv = hdd_request_priv(hdd_request);
1955 rc = priv->status;
1956 if (rc) {
1957 hdd_err("Operation failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958 goto end;
1959 }
1960
1961 /* fall through */
1962end:
Jeff Johnson7af334b2017-02-01 13:03:43 -08001963 hdd_request_put(hdd_request);
1964
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965 return rc;
1966}
1967
1968/**
1969 * wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd
1970 * @wiphy: pointer to the wiphy
1971 * @wdev: pointer to the wdev
1972 * @data: The netlink data
1973 * @data_len: The length of the netlink data in bytes
1974 *
1975 * Return: 0 on success.
1976 */
1977int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy,
1978 struct wireless_dev *wdev,
1979 const void *data,
1980 int data_len)
1981{
1982 int ret;
1983
1984 cds_ssr_protect(__func__);
1985 ret = __wlan_hdd_cfg80211_dcc_update_ndl(wiphy, wdev,
1986 data, data_len);
1987 cds_ssr_unprotect(__func__);
1988
1989 return ret;
1990}
1991
1992/**
1993 * wlan_hdd_dcc_stats_event_callback() - Callback to get stats event
1994 * @context_ptr: request context
1995 * @response_ptr: response data
1996 */
1997static void wlan_hdd_dcc_stats_event_callback(void *context_ptr,
1998 void *response_ptr)
1999{
2000 hdd_context_t *hdd_ctx = (hdd_context_t *)context_ptr;
2001 struct sir_dcc_get_stats_response *resp = response_ptr;
2002 struct sk_buff *vendor_event;
2003
2004 ENTER();
2005
2006 vendor_event =
2007 cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2008 NULL, sizeof(uint32_t) + resp->channel_stats_array_len +
2009 NLMSG_HDRLEN,
2010 QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX,
2011 GFP_KERNEL);
2012
2013 if (!vendor_event) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07002014 hdd_err("cfg80211_vendor_event_alloc failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002015 return;
2016 }
2017
2018 if (nla_put_u32(vendor_event,
2019 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT,
2020 resp->num_channels) ||
2021 nla_put(vendor_event,
2022 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY,
2023 resp->channel_stats_array_len,
2024 resp->channel_stats_array)) {
Jeff Johnson5f735d52016-07-06 15:14:45 -07002025 hdd_err("nla put failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002026 kfree_skb(vendor_event);
2027 return;
2028 }
2029
2030 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2031}
2032
2033/**
2034 * wlan_hdd_dcc_register_for_dcc_stats_event() - Register for dcc stats events
2035 * @hdd_ctx: hdd context
2036 */
2037void wlan_hdd_dcc_register_for_dcc_stats_event(hdd_context_t *hdd_ctx)
2038{
2039 int rc;
2040
2041 rc = sme_register_for_dcc_stats_event(hdd_ctx->hHal, hdd_ctx,
Arun Khandavalli4b55da72016-07-19 19:55:01 +05302042 wlan_hdd_dcc_stats_event_callback);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002043 if (rc)
Jeff Johnson5f735d52016-07-06 15:14:45 -07002044 hdd_err("Register callback failed: %d", rc);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002045}