blob: a34959d2f292614506ae39b15d021cf23f1971ba [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
3 *
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"
39#include "wlan_tgt_def_config.h"
40#include "sch_api.h"
41#include "wma_api.h"
42
43/* Structure definitions for WLAN_SET_DOT11P_CHANNEL_SCHED */
44#define AIFSN_MIN (2)
45#define AIFSN_MAX (15)
46#define CW_MIN (1)
47#define CW_MAX (10)
48
49/* Maximum time(ms) to wait for OCB operations */
50#define WLAN_WAIT_TIME_OCB_CMD 1500
51#define HDD_OCB_MAGIC 0x489a154f
52
53/**
54 * struct hdd_ocb_ctxt - Context for OCB operations
55 * adapter: the ocb adapter
56 * completion_evt: the completion event
57 * status: status of the request
58 */
59struct hdd_ocb_ctxt {
60 uint32_t magic;
61 hdd_adapter_t *adapter;
62 struct completion completion_evt;
63 int status;
64};
65
66/**
67 * hdd_set_dot11p_config() - Set 802.11p config flag
68 * @hdd_ctx: HDD Context pointer
69 *
70 * TODO-OCB: This has been temporarily added to ensure this paramter
71 * is set in CSR when we init the channel list. This should be removed
72 * once the 5.9 GHz channels are added to the regulatory domain.
73 */
74void hdd_set_dot11p_config(hdd_context_t *hdd_ctx)
75{
76 sme_set_dot11p_config(hdd_ctx->hHal,
77 hdd_ctx->config->dot11p_mode !=
78 WLAN_HDD_11P_DISABLED);
79}
80
81/**
82 * dot11p_validate_qos_params() - Check if QoS parameters are valid
83 * @qos_params: Array of QoS parameters
84 *
85 * Return: 0 on success. error code on failure.
86 */
87static int dot11p_validate_qos_params(struct sir_qos_params qos_params[])
88{
89 int i;
90
91 for (i = 0; i < MAX_NUM_AC; i++) {
92 if ((!qos_params[i].aifsn) && (!qos_params[i].cwmin)
93 && (!qos_params[i].cwmax))
94 continue;
95
96 /* Validate AIFSN */
97 if ((qos_params[i].aifsn < AIFSN_MIN)
98 || (qos_params[i].aifsn > AIFSN_MAX)) {
99 hddLog(LOGE, FL("Invalid QoS parameter aifsn %d"),
100 qos_params[i].aifsn);
101 return -EINVAL;
102 }
103
104 /* Validate CWMin */
105 if ((qos_params[i].cwmin < CW_MIN)
106 || (qos_params[i].cwmin > CW_MAX)) {
107 hddLog(LOGE, FL("Invalid QoS parameter cwmin %d"),
108 qos_params[i].cwmin);
109 return -EINVAL;
110 }
111
112 /* Validate CWMax */
113 if ((qos_params[i].cwmax < CW_MIN)
114 || (qos_params[i].cwmax > CW_MAX)) {
115 hddLog(LOGE, FL("Invalid QoS parameter cwmax %d"),
116 qos_params[i].cwmax);
117 return -EINVAL;
118 }
119 }
120
121 return 0;
122}
123
124#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) || \
125 defined(FEATURE_STATICALLY_ADD_11P_CHANNELS)
126/*
127 * If FEATURE_STATICALLY_ADD_11P_CHANNELS
128 * is defined, IEEE80211_CHAN_NO_10MHZ,
129 * and IEEE80211_CHAN_NO_20MHZ won't
130 * be defined.
131 */
132#define IEEE80211_CHAN_NO_20MHZ (1<<11)
133#define IEEE80211_CHAN_NO_10MHZ (1<<12)
134#endif
135
136#ifdef FEATURE_STATICALLY_ADD_11P_CHANNELS
137
138#define DOT11P_TX_PWR_MAX 30
139#define DOT11P_TX_ANTENNA_MAX 6
140#define NUM_DOT11P_CHANNELS 10
141/**
142 * struct chan_info - information for the channel
143 * @center_freq: center frequency
144 * @max_bandwidth: maximum bandwidth of the channel in MHz
145 */
146struct chan_info {
147 uint32_t center_freq;
148 uint32_t max_bandwidth;
149};
150
151struct chan_info valid_dot11p_channels[NUM_DOT11P_CHANNELS] = {
152 {5860, 10},
153 {5870, 10},
154 {5880, 10},
155 {5890, 10},
156 {5900, 10},
157 {5910, 10},
158 {5920, 10},
159 {5875, 20},
160 {5905, 20},
161 {5852, 5}
162};
163
164/**
165 * dot11p_validate_channel_static_channels() - validate a DSRC channel
166 * @center_freq: the channel's center frequency
167 * @bandwidth: the channel's bandwidth
168 * @tx_power: transmit power
169 * @reg_power: (output) the max tx power from the regulatory domain
170 * @antenna_max: (output) the max antenna gain from the regulatory domain
171 *
172 * This function of the function checks the channel parameters against a
173 * hardcoded list of valid channels based on the FCC rules.
174 *
175 * Return: 0 if the channel is valid, error code otherwise.
176 */
177static int dot11p_validate_channel_static_channels(struct wiphy *wiphy,
178 uint32_t channel_freq, uint32_t bandwidth, uint32_t tx_power,
179 uint8_t *reg_power, uint8_t *antenna_max)
180{
181 int i;
182
183 for (i = 0; i < NUM_DOT11P_CHANNELS; i++) {
184 if (channel_freq == valid_dot11p_channels[i].center_freq) {
185 if (reg_power)
186 *reg_power = DOT11P_TX_PWR_MAX;
187 if (antenna_max)
188 *antenna_max = DOT11P_TX_ANTENNA_MAX;
189
190 if (bandwidth == 0)
191 bandwidth =
192 valid_dot11p_channels[i].max_bandwidth;
193 else if (bandwidth >
194 valid_dot11p_channels[i].max_bandwidth)
195 return -EINVAL;
196
197 if (bandwidth != 5 && bandwidth != 10 &&
198 bandwidth != 20)
199 return -EINVAL;
200 if (tx_power > DOT11P_TX_PWR_MAX)
201 return -EINVAL;
202
203 return 0;
204 }
205 }
206
207 return -EINVAL;
208}
209#else
210/**
211 * dot11p_validate_channel_static_channels() - validate a DSRC channel
212 * @center_freq: the channel's center frequency
213 * @bandwidth: the channel's bandwidth
214 * @tx_power: transmit power
215 * @reg_power: (output) the max tx power from the regulatory domain
216 * @antenna_max: (output) the max antenna gain from the regulatory domain
217 *
218 * This function of the function checks the channel parameters against a
219 * hardcoded list of valid channels based on the FCC rules.
220 *
221 * Return: 0 if the channel is valid, error code otherwise.
222 */
223static int dot11p_validate_channel_static_channels(struct wiphy *wiphy,
224 uint32_t channel_freq, uint32_t bandwidth, uint32_t tx_power,
225 uint8_t *reg_power, uint8_t *antenna_max)
226{
227 return -EINVAL;
228}
229#endif /* FEATURE_STATICALLY_ADD_11P_CHANNELS */
230
231/**
232 * dot11p_validate_channel() - validates a DSRC channel
233 * @center_freq: the channel's center frequency
234 * @bandwidth: the channel's bandwidth
235 * @tx_power: transmit power
236 * @reg_power: (output) the max tx power from the regulatory domain
237 * @antenna_max: (output) the max antenna gain from the regulatory domain
238 *
239 * Return: 0 if the channel is valid, error code otherwise.
240 */
241static int dot11p_validate_channel(struct wiphy *wiphy,
242 uint32_t channel_freq, uint32_t bandwidth,
243 uint32_t tx_power, uint8_t *reg_power,
244 uint8_t *antenna_max)
245{
246 int band_idx, channel_idx;
247 struct ieee80211_supported_band *current_band;
248 struct ieee80211_channel *current_channel;
249
250 for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) {
251 current_band = wiphy->bands[band_idx];
252 if (!current_band)
253 continue;
254
255 for (channel_idx = 0; channel_idx < current_band->n_channels;
256 channel_idx++) {
257 current_channel = &current_band->channels[channel_idx];
258
259 if (channel_freq == current_channel->center_freq) {
260 if (current_channel->flags &
261 IEEE80211_CHAN_DISABLED)
262 return -EINVAL;
263
264 if (reg_power)
265 *reg_power =
266 current_channel->max_reg_power;
267 if (antenna_max)
268 *antenna_max =
269 current_channel->
270 max_antenna_gain;
271
272 switch (bandwidth) {
273 case 0:
274 if (current_channel->flags &
275 IEEE80211_CHAN_NO_10MHZ)
276 bandwidth = 5;
277 else if (current_channel->flags &
278 IEEE80211_CHAN_NO_20MHZ)
279 bandwidth = 10;
280 else
281 bandwidth = 20;
282 break;
283 case 5:
284 break;
285 case 10:
286 if (current_channel->flags &
287 IEEE80211_CHAN_NO_10MHZ)
288 return -EINVAL;
289 break;
290 case 20:
291 if (current_channel->flags &
292 IEEE80211_CHAN_NO_20MHZ)
293 return -EINVAL;
294 break;
295 default:
296 return -EINVAL;
297 }
298
299 if (tx_power > current_channel->max_power)
300 return -EINVAL;
301
302 return 0;
303 }
304 }
305 }
306
307 return dot11p_validate_channel_static_channels(wiphy, channel_freq,
308 bandwidth, tx_power, reg_power, antenna_max);
309}
310
311/**
312 * hdd_ocb_validate_config() - Validates the config data
313 * @config: configuration to be validated
314 *
315 * Return: 0 on success.
316 */
317static int hdd_ocb_validate_config(hdd_adapter_t *adapter,
318 struct sir_ocb_config *config)
319{
320 int i;
321 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
322
323 for (i = 0; i < config->channel_count; i++) {
324 if (dot11p_validate_channel(hdd_ctx->wiphy,
325 config->channels[i].chan_freq,
326 config->channels[i].bandwidth,
327 config->channels[i].max_pwr,
328 &config->channels[i].reg_pwr,
329 &config->channels[i].antenna_max)) {
330 hddLog(LOGE, FL("Invalid channel frequency %d"),
331 config->channels[i].chan_freq);
332 return -EINVAL;
333 }
334 if (dot11p_validate_qos_params(config->channels[i].qos_params))
335 return -EINVAL;
336 }
337
338 return 0;
339}
340
341/**
342 * hdd_ocb_register_sta() - Register station with Transport Layer
343 * @adapter: Pointer to HDD Adapter
344 *
345 * This function should be invoked in the OCB Set Schedule callback
346 * to enable the data path in the TL by calling RegisterSTAClient
347 *
348 * Return: 0 on success. -1 on failure.
349 */
350static int hdd_ocb_register_sta(hdd_adapter_t *adapter)
351{
352 CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE;
353 struct ol_txrx_desc_type sta_desc = {0};
354 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
355 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
356 uint8_t peer_id;
357
358 cdf_status = ol_txrx_register_ocb_peer(hdd_ctx->pcds_context,
359 adapter->macAddressCurrent.bytes,
360 &peer_id);
361 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
362 hddLog(LOGE, FL("Error registering OCB Self Peer!"));
363 return -EINVAL;
364 }
365
366 hdd_ctx->sta_to_adapter[peer_id] = adapter;
367
368 sta_desc.sta_id = peer_id;
369 sta_desc.is_qos_enabled = 1;
370
371 cdf_status = ol_txrx_register_peer(hdd_rx_packet_cbk,
372 &sta_desc);
373 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
374 hddLog(LOGE, FL("Failed to register. Status= %d [0x%08X]"),
375 cdf_status, cdf_status);
376 return -EINVAL;
377 }
378
379 if (pHddStaCtx->conn_info.staId[0] != 0 &&
380 pHddStaCtx->conn_info.staId[0] != peer_id) {
381 hddLog(LOGE, FL("The ID for the OCB station has changed."));
382 }
383
384 pHddStaCtx->conn_info.staId[0] = peer_id;
385 cdf_copy_macaddr(&pHddStaCtx->conn_info.peerMacAddress[0],
386 &adapter->macAddressCurrent);
387
388 return 0;
389}
390
391/**
392 * hdd_ocb_config_new() - Creates a new OCB configuration
393 * @num_channels: the number of channels
394 * @num_schedule: the schedule size
395 * @ndl_chan_list_len: length in bytes of the NDL chan blob
396 * @ndl_active_state_list_len: length in bytes of the active state blob
397 *
398 * Return: A pointer to the OCB configuration struct, NULL on failure.
399 */
400static struct sir_ocb_config *hdd_ocb_config_new(int num_channels,
401 int num_schedule,
402 int ndl_chan_list_len,
403 int ndl_active_state_list_len)
404{
405 struct sir_ocb_config *ret = 0;
406 uint32_t len;
407 void *cursor;
408
409 if (num_channels > CFG_TGT_NUM_OCB_CHANNELS ||
410 num_schedule > CFG_TGT_NUM_OCB_SCHEDULES)
411 return NULL;
412
413 len = sizeof(*ret) +
414 num_channels * sizeof(struct sir_ocb_config_channel) +
415 num_schedule * sizeof(struct sir_ocb_config_sched) +
416 ndl_chan_list_len +
417 ndl_active_state_list_len;
418
419 cursor = cdf_mem_malloc(len);
420 if (!cursor)
421 goto fail;
422
423 cdf_mem_zero(cursor, len);
424 ret = cursor;
425 cursor += sizeof(*ret);
426
427 ret->channel_count = num_channels;
428 ret->channels = cursor;
429 cursor += num_channels * sizeof(*ret->channels);
430
431 ret->schedule_size = num_schedule;
432 ret->schedule = cursor;
433 cursor += num_schedule * sizeof(*ret->schedule);
434
435 ret->dcc_ndl_chan_list = cursor;
436 cursor += ndl_chan_list_len;
437
438 ret->dcc_ndl_active_state_list = cursor;
439 cursor += ndl_active_state_list_len;
440
441 return ret;
442
443fail:
444 cdf_mem_free(ret);
445 return NULL;
446}
447
448/**
449 * hdd_ocb_set_config_callback() - OCB set config callback function
450 * @context_ptr: OCB call context
451 * @response_ptr: Pointer to response structure
452 *
453 * This function is registered as a callback with the lower layers
454 * and is used to respond with the status of a OCB set config command.
455 */
456static void hdd_ocb_set_config_callback(void *context_ptr, void *response_ptr)
457{
458 struct hdd_ocb_ctxt *context = context_ptr;
459 struct sir_ocb_set_config_response *resp = response_ptr;
460
461 if (!context)
462 return;
463
464 if (resp && resp->status)
465 hddLog(LOGE, FL("Operation failed: %d"), resp->status);
466
467 spin_lock(&hdd_context_lock);
468 if (context->magic == HDD_OCB_MAGIC) {
469 hdd_adapter_t *adapter = context->adapter;
470 if (!resp) {
471 context->status = -EINVAL;
472 complete(&context->completion_evt);
473 spin_unlock(&hdd_context_lock);
474 return;
475 }
476
477 context->adapter->ocb_set_config_resp = *resp;
478 spin_unlock(&hdd_context_lock);
479 if (!resp->status) {
480 /*
481 * OCB set config command successful.
482 * Open the TX data path
483 */
484 if (!hdd_ocb_register_sta(adapter)) {
485 netif_carrier_on(adapter->dev);
486 netif_tx_start_all_queues(
487 adapter->dev);
488 }
489 }
490
491 spin_lock(&hdd_context_lock);
492 if (context->magic == HDD_OCB_MAGIC)
493 complete(&context->completion_evt);
494 spin_unlock(&hdd_context_lock);
495 } else {
496 spin_unlock(&hdd_context_lock);
497 }
498}
499
500/**
501 * hdd_ocb_set_config_req() - Send an OCB set config request
502 * @adapter: a pointer to the adapter
503 * @config: a pointer to the OCB configuration
504 *
505 * Return: 0 on success.
506 */
507static int hdd_ocb_set_config_req(hdd_adapter_t *adapter,
508 struct sir_ocb_config *config)
509{
510 int rc;
511 CDF_STATUS cdf_status;
512 struct hdd_ocb_ctxt context = {0};
513
514 if (hdd_ocb_validate_config(adapter, config)) {
515 hddLog(LOGE, FL("The configuration is invalid"));
516 return -EINVAL;
517 }
518
519 init_completion(&context.completion_evt);
520 context.adapter = adapter;
521 context.magic = HDD_OCB_MAGIC;
522
523 hddLog(LOG1, FL("Disabling queues"));
524 netif_tx_disable(adapter->dev);
525 netif_carrier_off(adapter->dev);
526
527 /* Call the SME API to set the config */
528 cdf_status = sme_ocb_set_config(
529 ((hdd_context_t *)adapter->pHddCtx)->hHal, &context,
530 hdd_ocb_set_config_callback, config);
531 if (cdf_status != CDF_STATUS_SUCCESS) {
532 hddLog(LOGE, FL("Error calling SME function."));
533 /* Convert from ecdf_status to errno */
534 return -EINVAL;
535 }
536
537 /* Wait for the function to complete. */
538 rc = wait_for_completion_timeout(&context.completion_evt,
539 msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD));
540 if (rc == 0) {
541 rc = -ETIMEDOUT;
542 goto end;
543 }
544 rc = 0;
545
546 if (context.status) {
547 rc = context.status;
548 goto end;
549 }
550
551 if (adapter->ocb_set_config_resp.status) {
552 rc = -EINVAL;
553 goto end;
554 }
555
556 /* fall through */
557end:
558 spin_lock(&hdd_context_lock);
559 context.magic = 0;
560 spin_unlock(&hdd_context_lock);
561 if (rc)
562 hddLog(LOGE, FL("Operation failed: %d"), rc);
563 return rc;
564}
565
566/**
567 * __iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED
568 * ioctl
569 * @dev: Pointer to net_device structure
570 * @iw_request_info: IW Request Info
571 * @wrqu: IW Request Userspace Data Pointer
572 * @extra: IW Request Kernel Data Pointer
573 *
574 * Return: 0 on success
575 */
576static int __iw_set_dot11p_channel_sched(struct net_device *dev,
577 struct iw_request_info *info,
578 union iwreq_data *wrqu, char *extra)
579{
580 int rc = 0;
581 struct dot11p_channel_sched *sched;
582 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
583 struct sir_ocb_config *config = NULL;
584 uint8_t *mac_addr;
585 int i, j;
586 struct sir_ocb_config_channel *curr_chan;
587
588 if (wlan_hdd_validate_context(WLAN_HDD_GET_CTX(adapter))) {
589 hddLog(LOGE, FL("HDD context is not valid"));
590 return -EINVAL;
591 }
592
593 if (adapter->device_mode != WLAN_HDD_OCB) {
594 hddLog(LOGE, FL("Device not in OCB mode!"));
595 return -EINVAL;
596 }
597
598 sched = (struct dot11p_channel_sched *)extra;
599
600 /* Scheduled slots same as num channels for compatibility */
601 config = hdd_ocb_config_new(sched->num_channels, sched->num_channels,
602 0, 0);
603 if (config == NULL) {
604 hddLog(LOGE, FL("Failed to allocate memory!"));
605 return -ENOMEM;
606 }
607
608 /* Identify the vdev interface */
609 config->session_id = adapter->sessionId;
610
611 /* Release all the mac addresses used for OCB */
612 for (i = 0; i < adapter->ocb_mac_addr_count; i++) {
613 wlan_hdd_release_intf_addr(adapter->pHddCtx,
614 adapter->ocb_mac_address[i]);
615 }
616 adapter->ocb_mac_addr_count = 0;
617
618 config->channel_count = 0;
619 for (i = 0; i < sched->num_channels; i++) {
620 if (0 == sched->channels[i].channel_freq)
621 continue;
622
623 curr_chan = &(config->channels[config->channel_count]);
624
625 curr_chan->chan_freq = sched->channels[i].channel_freq;
626 /*
627 * tx_power is divided by 2 because ocb_channel.tx_power is
628 * in half dB increments and sir_ocb_config_channel.max_pwr
629 * is in 1 dB increments.
630 */
631 curr_chan->max_pwr = sched->channels[i].tx_power / 2;
632 curr_chan->bandwidth = sched->channels[i].channel_bandwidth;
633 /* assume 10 as default if not provided */
634 if (curr_chan->bandwidth == 0)
635 curr_chan->bandwidth = 10;
636
637 /*
638 * Setup locally administered mac addresses for each channel.
639 * First channel uses the adapter's address.
640 */
641 if (i == 0) {
642 cdf_mem_copy(curr_chan->mac_address,
643 adapter->macAddressCurrent.bytes,
644 sizeof(tSirMacAddr));
645 } else {
646 mac_addr = wlan_hdd_get_intf_addr(adapter->pHddCtx);
647 if (mac_addr == NULL) {
648 hddLog(LOGE, FL("Cannot obtain mac address"));
649 rc = -EINVAL;
650 goto fail;
651 }
652 cdf_mem_copy(config->channels[
653 config->channel_count].mac_address,
654 mac_addr, sizeof(tSirMacAddr));
655 /* Save the mac address to release later */
656 cdf_mem_copy(adapter->ocb_mac_address[
657 adapter->ocb_mac_addr_count],
658 mac_addr,
659 sizeof(adapter->ocb_mac_address[
660 adapter->ocb_mac_addr_count]));
661 adapter->ocb_mac_addr_count++;
662 }
663
664 for (j = 0; j < MAX_NUM_AC; j++) {
665 curr_chan->qos_params[j].aifsn =
666 sched->channels[i].qos_params[j].aifsn;
667 curr_chan->qos_params[j].cwmin =
668 sched->channels[i].qos_params[j].cwmin;
669 curr_chan->qos_params[j].cwmax =
670 sched->channels[i].qos_params[j].cwmax;
671 }
672
673 config->channel_count++;
674 }
675
676 /*
677 * Scheduled slots same as num channels for compatibility with
678 * legacy use.
679 */
680 for (i = 0; i < sched->num_channels; i++) {
681 config->schedule[i].chan_freq = sched->channels[i].channel_freq;
682 config->schedule[i].guard_interval =
683 sched->channels[i].start_guard_interval;
684 config->schedule[i].total_duration =
685 sched->channels[i].duration;
686 }
687
688 rc = hdd_ocb_set_config_req(adapter, config);
689 if (rc) {
690 hddLog(LOGE, FL("Error while setting OCB config"));
691 goto fail;
692 }
693
694 rc = 0;
695
696fail:
697 cdf_mem_free(config);
698 return rc;
699}
700
701/**
702 * iw_set_dot11p_channel_sched() - IOCTL interface for setting channel schedule
703 * @dev: Pointer to net_device structure
704 * @iw_request_info: IW Request Info
705 * @wrqu: IW Request Userspace Data Pointer
706 * @extra: IW Request Kernel Data Pointer
707 *
708 * Return: 0 on success.
709 */
710int iw_set_dot11p_channel_sched(struct net_device *dev,
711 struct iw_request_info *info,
712 union iwreq_data *wrqu, char *extra)
713{
714 int ret;
715
716 cds_ssr_protect(__func__);
717 ret = __iw_set_dot11p_channel_sched(dev, info, wrqu, extra);
718 cds_ssr_unprotect(__func__);
719
720 return ret;
721}
722
723static const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[
724 QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1] = {
725 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT] = {
726 .type = NLA_U32
727 },
728 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE] = {
729 .type = NLA_U32
730 },
731 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY] = {
732 .type = NLA_BINARY
733 },
734 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY] = {
735 .type = NLA_BINARY
736 },
737 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY] = {
738 .type = NLA_BINARY
739 },
740 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY] = {
741 .type = NLA_BINARY
742 },
743 [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS] = {
744 .type = NLA_U32
745 },
746};
747
748static const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[
749 QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1] = {
750 [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE] = {
751 .type = NLA_BINARY, .len = SIZE_UTC_TIME
752 },
753 [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR] = {
754 .type = NLA_BINARY, .len = SIZE_UTC_TIME_ERROR
755 },
756};
757
758static const struct nla_policy qca_wlan_vendor_ocb_start_timing_advert_policy[
759 QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1] = {
760 [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ] = {
761 .type = NLA_U32
762 },
763 [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE] = {
764 .type = NLA_U32
765 },
766};
767
768static const struct nla_policy qca_wlan_vendor_ocb_stop_timing_advert_policy[
769 QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1] = {
770 [QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ] = {
771 .type = NLA_U32
772 },
773};
774
775static const struct nla_policy qca_wlan_vendor_ocb_get_tsf_timer_resp[] = {
776 [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH] = {
777 .type = NLA_U32
778 },
779 [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW] = {
780 .type = NLA_U32
781 },
782};
783
784static const struct nla_policy qca_wlan_vendor_dcc_get_stats[] = {
785 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] = {
786 .type = NLA_U32
787 },
788 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY] = {
789 .type = NLA_BINARY
790 },
791};
792
793static const struct nla_policy qca_wlan_vendor_dcc_get_stats_resp[] = {
794 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT] = {
795 .type = NLA_U32
796 },
797 [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY] = {
798 .type = NLA_BINARY
799 },
800};
801
802static const struct nla_policy qca_wlan_vendor_dcc_clear_stats[] = {
803 [QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP] = {
804 .type = NLA_U32
805 },
806};
807
808static const struct nla_policy qca_wlan_vendor_dcc_update_ndl[
809 QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1] = {
810 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] = {
811 .type = NLA_U32
812 },
813 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] = {
814 .type = NLA_BINARY
815 },
816 [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY] = {
817 .type = NLA_BINARY
818 },
819};
820
821/**
822 * struct wlan_hdd_ocb_config_channel
823 * @chan_freq: frequency of the channel
824 * @bandwidth: bandwidth of the channel, either 10 or 20 MHz
825 * @mac_address: MAC address assigned to this channel
826 * @qos_params: QoS parameters
827 * @max_pwr: maximum transmit power of the channel (1/2 dBm)
828 * @min_pwr: minimum transmit power of the channel (1/2 dBm)
829 */
830struct wlan_hdd_ocb_config_channel {
831 uint32_t chan_freq;
832 uint32_t bandwidth;
833 uint16_t flags;
834 uint8_t reserved[4];
835 struct sir_qos_params qos_params[MAX_NUM_AC];
836 uint32_t max_pwr;
837 uint32_t min_pwr;
838};
839
840static void wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel(
841 struct sir_ocb_config_channel *dest,
842 struct wlan_hdd_ocb_config_channel *src,
843 uint32_t channel_count)
844{
845 uint32_t i;
846
847 cdf_mem_zero(dest, channel_count * sizeof(*dest));
848
849 for (i = 0; i < channel_count; i++) {
850 dest[i].chan_freq = src[i].chan_freq;
851 dest[i].bandwidth = src[i].bandwidth;
852 cdf_mem_copy(dest[i].qos_params, src[i].qos_params,
853 sizeof(dest[i].qos_params));
854 /*
855 * max_pwr and min_pwr are divided by 2 because
856 * wlan_hdd_ocb_config_channel.max_pwr and min_pwr
857 * are in 1/2 dB increments and
858 * sir_ocb_config_channel.max_pwr and min_pwr are in
859 * 1 dB increments.
860 */
861 dest[i].max_pwr = src[i].max_pwr / 2;
862 dest[i].min_pwr = (src[i].min_pwr + 1) / 2;
863 dest[i].flags = src[i].flags;
864 }
865}
866
867/**
868 * __wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command
869 * @wiphy: pointer to the wiphy
870 * @wdev: pointer to the wdev
871 * @data: The netlink data
872 * @data_len: The length of the netlink data in bytes
873 *
874 * Return: 0 on success.
875 */
876static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy,
877 struct wireless_dev *wdev,
878 const void *data,
879 int data_len)
880{
881 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
882 struct net_device *dev = wdev->netdev;
883 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
884 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1];
885 struct nlattr *channel_array;
886 struct nlattr *sched_array;
887 struct nlattr *ndl_chan_list;
888 uint32_t ndl_chan_list_len;
889 struct nlattr *ndl_active_state_list;
890 uint32_t ndl_active_state_list_len;
891 uint32_t flags = 0;
892 int i;
893 int channel_count, schedule_size;
894 struct sir_ocb_config *config;
895 int rc = -EINVAL;
896 uint8_t *mac_addr;
897
898 ENTER();
899
900 if (wlan_hdd_validate_context(hdd_ctx)) {
901 hddLog(LOGE, FL("HDD context is not valid"));
902 return -EINVAL;
903 }
904
905 if (adapter->device_mode != WLAN_HDD_OCB) {
906 hddLog(LOGE, FL("Device not in OCB mode!"));
907 return -EINVAL;
908 }
909
910 /* Parse the netlink message */
911 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX,
912 data,
913 data_len, qca_wlan_vendor_ocb_set_config_policy)) {
914 hddLog(LOGE, FL("Invalid ATTR"));
915 return -EINVAL;
916 }
917
918 /* Get the number of channels in the schedule */
919 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]) {
920 hddLog(LOGE, FL("CHANNEL_COUNT is not present"));
921 return -EINVAL;
922 }
923 channel_count = nla_get_u32(
924 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]);
925
926 /* Get the size of the channel schedule */
927 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]) {
928 hddLog(LOGE, FL("SCHEDULE_SIZE is not present"));
929 return -EINVAL;
930 }
931 schedule_size = nla_get_u32(
932 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]);
933
934 /* Get the ndl chan array and the ndl active state array. */
935 ndl_chan_list =
936 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY];
937 ndl_chan_list_len = (ndl_chan_list ? nla_len(ndl_chan_list) : 0);
938
939 ndl_active_state_list =
940 tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY];
941 ndl_active_state_list_len = (ndl_active_state_list ?
942 nla_len(ndl_active_state_list) : 0);
943
944 /* Get the flags */
945 if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS])
946 flags = nla_get_u32(tb[
947 QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]);
948
949 config = hdd_ocb_config_new(channel_count, schedule_size,
950 ndl_chan_list_len,
951 ndl_active_state_list_len);
952 if (config == NULL) {
953 hddLog(LOGE, FL("Failed to allocate memory!"));
954 return -ENOMEM;
955 }
956
957 config->channel_count = channel_count;
958 config->schedule_size = schedule_size;
959 config->flags = flags;
960
961 /* Read the channel array */
962 channel_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY];
963 if (!channel_array) {
964 hddLog(LOGE, FL("No channel present"));
965 goto fail;
966 }
967 if (nla_len(channel_array) != channel_count *
968 sizeof(struct wlan_hdd_ocb_config_channel)) {
969 hddLog(LOGE, FL("CHANNEL_ARRAY is not the correct size"));
970 goto fail;
971 }
972 wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel(
973 config->channels, nla_data(channel_array), channel_count);
974
975 /* Identify the vdev interface */
976 config->session_id = adapter->sessionId;
977
978 /* Release all the mac addresses used for OCB */
979 for (i = 0; i < adapter->ocb_mac_addr_count; i++) {
980 wlan_hdd_release_intf_addr(adapter->pHddCtx,
981 adapter->ocb_mac_address[i]);
982 }
983 adapter->ocb_mac_addr_count = 0;
984
985 /*
986 * Setup locally administered mac addresses for each channel.
987 * First channel uses the adapter's address.
988 */
989 for (i = 0; i < config->channel_count; i++) {
990 if (i == 0) {
991 cdf_mem_copy(config->channels[i].mac_address,
992 adapter->macAddressCurrent.bytes,
993 sizeof(tSirMacAddr));
994 } else {
995 mac_addr = wlan_hdd_get_intf_addr(adapter->pHddCtx);
996 if (mac_addr == NULL) {
997 hddLog(LOGE, FL("Cannot obtain mac address"));
998 goto fail;
999 }
1000 cdf_mem_copy(config->channels[i].mac_address,
1001 mac_addr, sizeof(tSirMacAddr));
1002 /* Save the mac address to release later */
1003 cdf_mem_copy(adapter->ocb_mac_address[
1004 adapter->ocb_mac_addr_count],
1005 config->channels[i].mac_address,
1006 sizeof(adapter->ocb_mac_address[
1007 adapter->ocb_mac_addr_count]));
1008 adapter->ocb_mac_addr_count++;
1009 }
1010 }
1011
1012 /* Read the schedule array */
1013 sched_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY];
1014 if (!sched_array) {
1015 hddLog(LOGE, FL("No channel present"));
1016 goto fail;
1017 }
1018 if (nla_len(sched_array) != schedule_size * sizeof(*config->schedule)) {
1019 hddLog(LOGE, FL("SCHEDULE_ARRAY is not the correct size"));
1020 goto fail;
1021 }
1022 cdf_mem_copy(config->schedule, nla_data(sched_array),
1023 nla_len(sched_array));
1024
1025 /* Copy the NDL chan array */
1026 if (ndl_chan_list_len) {
1027 config->dcc_ndl_chan_list_len = ndl_chan_list_len;
1028 cdf_mem_copy(config->dcc_ndl_chan_list, nla_data(ndl_chan_list),
1029 nla_len(ndl_chan_list));
1030 }
1031
1032 /* Copy the NDL active state array */
1033 if (ndl_active_state_list_len) {
1034 config->dcc_ndl_active_state_list_len =
1035 ndl_active_state_list_len;
1036 cdf_mem_copy(config->dcc_ndl_active_state_list,
1037 nla_data(ndl_active_state_list),
1038 nla_len(ndl_active_state_list));
1039 }
1040
1041 rc = hdd_ocb_set_config_req(adapter, config);
1042 if (rc)
1043 hddLog(LOGE, FL("Error while setting OCB config: %d"), rc);
1044
1045fail:
1046 cdf_mem_free(config);
1047 return rc;
1048}
1049
1050/**
1051 * wlan_hdd_cfg80211_ocb_set_config() - Interface for set config 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_config(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_config(wiphy, wdev, data, data_len);
1068 cds_ssr_unprotect(__func__);
1069
1070 return ret;
1071}
1072
1073/**
1074 * __wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for set UTC time command
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 __wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy,
1083 struct wireless_dev *wdev,
1084 const void *data,
1085 int data_len)
1086{
1087 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1088 struct net_device *dev = wdev->netdev;
1089 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1090 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1];
1091 struct nlattr *utc_attr;
1092 struct nlattr *time_error_attr;
1093 struct sir_ocb_utc *utc;
1094 int rc = -EINVAL;
1095
1096 ENTER();
1097
1098 if (wlan_hdd_validate_context(hdd_ctx)) {
1099 hddLog(LOGE, FL("HDD context is not valid"));
1100 return -EINVAL;
1101 }
1102
1103 if (adapter->device_mode != WLAN_HDD_OCB) {
1104 hddLog(LOGE, FL("Device not in OCB mode!"));
1105 return -EINVAL;
1106 }
1107
1108 if (!wma_is_vdev_up(adapter->sessionId)) {
1109 hddLog(LOGE, FL("The device has not been started"));
1110 return -EINVAL;
1111 }
1112
1113 /* Parse the netlink message */
1114 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX,
1115 data,
1116 data_len, qca_wlan_vendor_ocb_set_utc_time_policy)) {
1117 hddLog(LOGE, FL("Invalid ATTR"));
1118 return -EINVAL;
1119 }
1120
1121 /* Read the UTC time */
1122 utc_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE];
1123 if (!utc_attr) {
1124 hddLog(LOGE, FL("UTC_TIME is not present"));
1125 return -EINVAL;
1126 }
1127 if (nla_len(utc_attr) != SIZE_UTC_TIME) {
1128 hddLog(LOGE, FL("UTC_TIME is not the correct size"));
1129 return -EINVAL;
1130 }
1131
1132 /* Read the time error */
1133 time_error_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR];
1134 if (!time_error_attr) {
1135 hddLog(LOGE, FL("UTC_TIME is not present"));
1136 return -EINVAL;
1137 }
1138 if (nla_len(time_error_attr) != SIZE_UTC_TIME_ERROR) {
1139 hddLog(LOGE, FL("UTC_TIME is not the correct size"));
1140 return -EINVAL;
1141 }
1142
1143 utc = cdf_mem_malloc(sizeof(*utc));
1144 if (!utc) {
1145 hddLog(LOGE, FL("cdf_mem_malloc failed"));
1146 return -ENOMEM;
1147 }
1148 utc->vdev_id = adapter->sessionId;
1149 cdf_mem_copy(utc->utc_time, nla_data(utc_attr), SIZE_UTC_TIME);
1150 cdf_mem_copy(utc->time_error, nla_data(time_error_attr),
1151 SIZE_UTC_TIME_ERROR);
1152
1153 if (sme_ocb_set_utc_time(hdd_ctx->hHal, utc) != CDF_STATUS_SUCCESS) {
1154 hddLog(LOGE, FL("Error while setting UTC time"));
1155 rc = -EINVAL;
1156 } else {
1157 rc = 0;
1158 }
1159
1160 cdf_mem_free(utc);
1161 return rc;
1162}
1163
1164/**
1165 * wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for the set UTC time command
1166 * @wiphy: pointer to the wiphy
1167 * @wdev: pointer to the wdev
1168 * @data: The netlink data
1169 * @data_len: The length of the netlink data in bytes
1170 *
1171 * Return: 0 on success.
1172 */
1173int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy,
1174 struct wireless_dev *wdev,
1175 const void *data,
1176 int data_len)
1177{
1178 int ret;
1179
1180 cds_ssr_protect(__func__);
1181 ret = __wlan_hdd_cfg80211_ocb_set_utc_time(wiphy, wdev, data, data_len);
1182 cds_ssr_unprotect(__func__);
1183
1184 return ret;
1185}
1186
1187/**
1188 * __wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for start TA cmd
1189 * @wiphy: pointer to the wiphy
1190 * @wdev: pointer to the wdev
1191 * @data: The netlink data
1192 * @data_len: The length of the netlink data in bytes
1193 *
1194 * Return: 0 on success.
1195 */
1196static int
1197__wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy,
1198 struct wireless_dev *wdev,
1199 const void *data,
1200 int data_len)
1201{
1202 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1203 struct net_device *dev = wdev->netdev;
1204 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1205 tpAniSirGlobal mac_ctx = PMAC_STRUCT(WLAN_HDD_GET_HAL_CTX(adapter));
1206 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1];
1207 struct sir_ocb_timing_advert *timing_advert;
1208 int rc = -EINVAL;
1209
1210 ENTER();
1211
1212 if (wlan_hdd_validate_context(hdd_ctx)) {
1213 hddLog(LOGE, FL("HDD context is not valid"));
1214 return -EINVAL;
1215 }
1216
1217 if (adapter->device_mode != WLAN_HDD_OCB) {
1218 hddLog(LOGE, FL("Device not in OCB mode!"));
1219 return -EINVAL;
1220 }
1221
1222 if (!wma_is_vdev_up(adapter->sessionId)) {
1223 hddLog(LOGE, FL("The device has not been started"));
1224 return -EINVAL;
1225 }
1226
1227 timing_advert = cdf_mem_malloc(sizeof(*timing_advert));
1228 if (!timing_advert) {
1229 hddLog(LOGE, FL("cdf_mem_malloc failed"));
1230 return -ENOMEM;
1231 }
1232 cdf_mem_zero(timing_advert, sizeof(*timing_advert));
1233 timing_advert->vdev_id = adapter->sessionId;
1234
1235 /* Parse the netlink message */
1236 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX,
1237 data,
1238 data_len,
1239 qca_wlan_vendor_ocb_start_timing_advert_policy)) {
1240 hddLog(LOGE, FL("Invalid ATTR"));
1241 goto fail;
1242 }
1243
1244 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]) {
1245 hddLog(LOGE, FL("CHANNEL_FREQ is not present"));
1246 goto fail;
1247 }
1248 timing_advert->chan_freq = nla_get_u32(
1249 tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]);
1250
1251 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]) {
1252 hddLog(LOGE, FL("REPEAT_RATE is not present"));
1253 goto fail;
1254 }
1255 timing_advert->repeat_rate = nla_get_u32(
1256 tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]);
1257
1258 timing_advert->template_length =
1259 sch_gen_timing_advert_frame(mac_ctx,
1260 *(tSirMacAddr *)&adapter->macAddressCurrent.bytes,
1261 &timing_advert->template_value,
1262 &timing_advert->timestamp_offset,
1263 &timing_advert->time_value_offset);
1264 if (timing_advert->template_length <= 0) {
1265 hddLog(LOGE, FL("Error while generating the TA frame"));
1266 goto fail;
1267 }
1268
1269 if (sme_ocb_start_timing_advert(hdd_ctx->hHal, timing_advert) !=
1270 CDF_STATUS_SUCCESS) {
1271 hddLog(LOGE, FL("Error while starting timing advert"));
1272 rc = -EINVAL;
1273 } else {
1274 rc = 0;
1275 }
1276
1277fail:
1278 if (timing_advert->template_value)
1279 cdf_mem_free(timing_advert->template_value);
1280 cdf_mem_free(timing_advert);
1281 return rc;
1282}
1283
1284/**
1285 * wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for the start TA cmd
1286 * @wiphy: pointer to the wiphy
1287 * @wdev: pointer to the wdev
1288 * @data: The netlink data
1289 * @data_len: The length of the netlink data in bytes
1290 *
1291 * Return: 0 on success.
1292 */
1293int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy,
1294 struct wireless_dev *wdev,
1295 const void *data,
1296 int data_len)
1297{
1298 int ret;
1299
1300 cds_ssr_protect(__func__);
1301 ret = __wlan_hdd_cfg80211_ocb_start_timing_advert(wiphy, wdev,
1302 data, data_len);
1303 cds_ssr_unprotect(__func__);
1304
1305 return ret;
1306}
1307
1308/**
1309 * __wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd
1310 * @wiphy: pointer to the wiphy
1311 * @wdev: pointer to the wdev
1312 * @data: The netlink data
1313 * @data_len: The length of the netlink data in bytes
1314 *
1315 * Return: 0 on success.
1316 */
1317static int
1318__wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy,
1319 struct wireless_dev *wdev,
1320 const void *data,
1321 int data_len)
1322{
1323 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1324 struct net_device *dev = wdev->netdev;
1325 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1326 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1];
1327 struct sir_ocb_timing_advert *timing_advert;
1328 int rc = -EINVAL;
1329
1330 ENTER();
1331
1332 if (wlan_hdd_validate_context(hdd_ctx)) {
1333 hddLog(LOGE, FL("HDD context is not valid"));
1334 return -EINVAL;
1335 }
1336
1337 if (adapter->device_mode != WLAN_HDD_OCB) {
1338 hddLog(LOGE, FL("Device not in OCB mode!"));
1339 return -EINVAL;
1340 }
1341
1342 if (!wma_is_vdev_up(adapter->sessionId)) {
1343 hddLog(LOGE, FL("The device has not been started"));
1344 return -EINVAL;
1345 }
1346
1347 timing_advert = cdf_mem_malloc(sizeof(*timing_advert));
1348 if (!timing_advert) {
1349 hddLog(LOGE, FL("cdf_mem_malloc failed"));
1350 return -ENOMEM;
1351 }
1352 cdf_mem_zero(timing_advert, sizeof(sizeof(*timing_advert)));
1353 timing_advert->vdev_id = adapter->sessionId;
1354
1355 /* Parse the netlink message */
1356 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX,
1357 data,
1358 data_len,
1359 qca_wlan_vendor_ocb_stop_timing_advert_policy)) {
1360 hddLog(LOGE, FL("Invalid ATTR"));
1361 goto fail;
1362 }
1363
1364 if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]) {
1365 hddLog(LOGE, FL("CHANNEL_FREQ is not present"));
1366 goto fail;
1367 }
1368 timing_advert->chan_freq = nla_get_u32(
1369 tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]);
1370
1371 if (sme_ocb_stop_timing_advert(hdd_ctx->hHal, timing_advert) !=
1372 CDF_STATUS_SUCCESS) {
1373 hddLog(LOGE, FL("Error while stopping timing advert"));
1374 rc = -EINVAL;
1375 } else {
1376 rc = 0;
1377 }
1378
1379fail:
1380 cdf_mem_free(timing_advert);
1381 return rc;
1382}
1383
1384/**
1385 * wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd
1386 * @wiphy: pointer to the wiphy
1387 * @wdev: pointer to the wdev
1388 * @data: The netlink data
1389 * @data_len: The length of the netlink data in bytes
1390 *
1391 * Return: 0 on success.
1392 */
1393int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy,
1394 struct wireless_dev *wdev,
1395 const void *data,
1396 int data_len)
1397{
1398 int ret;
1399
1400 cds_ssr_protect(__func__);
1401 ret = __wlan_hdd_cfg80211_ocb_stop_timing_advert(wiphy, wdev,
1402 data, data_len);
1403 cds_ssr_unprotect(__func__);
1404
1405 return ret;
1406}
1407
1408/**
1409 * hdd_ocb_get_tsf_timer_callback() - Callback to get TSF command
1410 * @context_ptr: request context
1411 * @response_ptr: response data
1412 */
1413static void hdd_ocb_get_tsf_timer_callback(void *context_ptr,
1414 void *response_ptr)
1415{
1416 struct hdd_ocb_ctxt *context = context_ptr;
1417 struct sir_ocb_get_tsf_timer_response *response = response_ptr;
1418
1419 if (!context)
1420 return;
1421
1422 spin_lock(&hdd_context_lock);
1423 if (context->magic == HDD_OCB_MAGIC) {
1424 if (response) {
1425 context->adapter->ocb_get_tsf_timer_resp = *response;
1426 context->status = 0;
1427 } else {
1428 context->status = -EINVAL;
1429 }
1430 complete(&context->completion_evt);
1431 }
1432 spin_unlock(&hdd_context_lock);
1433}
1434
1435/**
1436 * __wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd
1437 * @wiphy: pointer to the wiphy
1438 * @wdev: pointer to the wdev
1439 * @data: The netlink data
1440 * @data_len: The length of the netlink data in bytes
1441 *
1442 * Return: 0 on success.
1443 */
1444static int
1445__wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy,
1446 struct wireless_dev *wdev,
1447 const void *data,
1448 int data_len)
1449{
1450 struct sk_buff *nl_resp = 0;
1451 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1452 struct net_device *dev = wdev->netdev;
1453 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1454 int rc = -EINVAL;
1455 struct sir_ocb_get_tsf_timer request = {0};
1456 struct hdd_ocb_ctxt context = {0};
1457
1458 ENTER();
1459
1460 if (wlan_hdd_validate_context(hdd_ctx)) {
1461 hddLog(LOGE, FL("HDD context is not valid"));
1462 return -EINVAL;
1463 }
1464
1465 if (adapter->device_mode != WLAN_HDD_OCB) {
1466 hddLog(LOGE, FL("Device not in OCB mode!"));
1467 return -EINVAL;
1468 }
1469
1470 if (!wma_is_vdev_up(adapter->sessionId)) {
1471 hddLog(LOGE, FL("The device has not been started"));
1472 return -EINVAL;
1473 }
1474
1475 /* Initialize the callback context */
1476 init_completion(&context.completion_evt);
1477 context.adapter = adapter;
1478 context.magic = HDD_OCB_MAGIC;
1479
1480 request.vdev_id = adapter->sessionId;
1481 /* Call the SME function */
1482 rc = sme_ocb_get_tsf_timer(hdd_ctx->hHal, &context,
1483 hdd_ocb_get_tsf_timer_callback,
1484 &request);
1485 if (rc) {
1486 hddLog(LOGE, FL("Error calling SME function"));
1487 /* Need to convert from ecdf_status to errno. */
1488 return -EINVAL;
1489 }
1490
1491 rc = wait_for_completion_timeout(&context.completion_evt,
1492 msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD));
1493 if (rc == 0) {
1494 hddLog(LOGE, FL("Operation timed out"));
1495 rc = -ETIMEDOUT;
1496 goto end;
1497 }
1498 rc = 0;
1499
1500 if (context.status) {
1501 hddLog(LOGE, FL("Operation failed: %d"), context.status);
1502 rc = context.status;
1503 goto end;
1504 }
1505
1506 /* Allocate the buffer for the response. */
1507 nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1508 2 * sizeof(uint32_t) + NLMSG_HDRLEN);
1509
1510 if (!nl_resp) {
1511 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
1512 rc = -ENOMEM;
1513 goto end;
1514 }
1515
1516 hddLog(LOGE, FL("Got TSF timer response, high=%d, low=%d"),
1517 adapter->ocb_get_tsf_timer_resp.timer_high,
1518 adapter->ocb_get_tsf_timer_resp.timer_low);
1519
1520 /* Populate the response. */
1521 rc = nla_put_u32(nl_resp,
1522 QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH,
1523 adapter->ocb_get_tsf_timer_resp.timer_high);
1524 if (rc)
1525 goto end;
1526 rc = nla_put_u32(nl_resp,
1527 QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW,
1528 adapter->ocb_get_tsf_timer_resp.timer_low);
1529 if (rc)
1530 goto end;
1531
1532 /* Send the response. */
1533 rc = cfg80211_vendor_cmd_reply(nl_resp);
1534 nl_resp = NULL;
1535 if (rc) {
1536 hddLog(LOGE, FL("cfg80211_vendor_cmd_reply failed: %d"), rc);
1537 goto end;
1538 }
1539
1540end:
1541 spin_lock(&hdd_context_lock);
1542 context.magic = 0;
1543 spin_unlock(&hdd_context_lock);
1544 if (nl_resp)
1545 kfree_skb(nl_resp);
1546 return rc;
1547}
1548
1549/**
1550 * wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd
1551 * @wiphy: pointer to the wiphy
1552 * @wdev: pointer to the wdev
1553 * @data: The netlink data
1554 * @data_len: The length of the netlink data in bytes
1555 *
1556 * Return: 0 on success.
1557 */
1558int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy,
1559 struct wireless_dev *wdev,
1560 const void *data,
1561 int data_len)
1562{
1563 int ret;
1564
1565 cds_ssr_protect(__func__);
1566 ret = __wlan_hdd_cfg80211_ocb_get_tsf_timer(wiphy, wdev,
1567 data, data_len);
1568 cds_ssr_unprotect(__func__);
1569
1570 return ret;
1571}
1572
1573/**
1574 * hdd_dcc_get_stats_callback() - Callback to get stats command
1575 * @context_ptr: request context
1576 * @response_ptr: response data
1577 */
1578static void hdd_dcc_get_stats_callback(void *context_ptr, void *response_ptr)
1579{
1580 struct hdd_ocb_ctxt *context = context_ptr;
1581 struct sir_dcc_get_stats_response *response = response_ptr;
1582 struct sir_dcc_get_stats_response *hdd_resp;
1583
1584 if (!context)
1585 return;
1586
1587 spin_lock(&hdd_context_lock);
1588 if (context->magic == HDD_OCB_MAGIC) {
1589 if (response) {
1590 /*
1591 * If the response is hanging around from the previous
1592 * request, delete it
1593 */
1594 if (context->adapter->dcc_get_stats_resp) {
1595 cdf_mem_free(
1596 context->adapter->dcc_get_stats_resp);
1597 }
1598 context->adapter->dcc_get_stats_resp =
1599 cdf_mem_malloc(sizeof(
1600 *context->adapter->dcc_get_stats_resp) +
1601 response->channel_stats_array_len);
1602 if (context->adapter->dcc_get_stats_resp) {
1603 hdd_resp = context->adapter->dcc_get_stats_resp;
1604 *hdd_resp = *response;
1605 hdd_resp->channel_stats_array =
1606 (void *)hdd_resp + sizeof(*hdd_resp);
1607 cdf_mem_copy(hdd_resp->channel_stats_array,
1608 response->channel_stats_array,
1609 response->channel_stats_array_len);
1610 context->status = 0;
1611 } else {
1612 context->status = -ENOMEM;
1613 }
1614 } else {
1615 context->status = -EINVAL;
1616 }
1617 complete(&context->completion_evt);
1618 }
1619 spin_unlock(&hdd_context_lock);
1620}
1621
1622/**
1623 * __wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats
1624 * @wiphy: pointer to the wiphy
1625 * @wdev: pointer to the wdev
1626 * @data: The netlink data
1627 * @data_len: The length of the netlink data in bytes
1628 *
1629 * Return: 0 on success.
1630 */
1631static int __wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy,
1632 struct wireless_dev *wdev,
1633 const void *data,
1634 int data_len)
1635{
1636 uint32_t channel_count = 0;
1637 uint32_t request_array_len = 0;
1638 void *request_array = 0;
1639 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1640 struct net_device *dev = wdev->netdev;
1641 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1642 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX + 1];
1643 struct sk_buff *nl_resp = 0;
1644 int rc = -EINVAL;
1645 struct sir_dcc_get_stats request = {0};
1646 struct hdd_ocb_ctxt context = {0};
1647
1648 ENTER();
1649
1650 if (wlan_hdd_validate_context(hdd_ctx)) {
1651 hddLog(LOGE, FL("HDD context is not valid"));
1652 return -EINVAL;
1653 }
1654
1655 if (adapter->device_mode != WLAN_HDD_OCB) {
1656 hddLog(LOGE, FL("Device not in OCB mode!"));
1657 return -EINVAL;
1658 }
1659
1660 if (!wma_is_vdev_up(adapter->sessionId)) {
1661 hddLog(LOGE, FL("The device has not been started"));
1662 return -EINVAL;
1663 }
1664
1665 /* Parse the netlink message */
1666 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX,
1667 data,
1668 data_len,
1669 qca_wlan_vendor_dcc_get_stats)) {
1670 hddLog(LOGE, FL("Invalid ATTR"));
1671 return -EINVAL;
1672 }
1673
1674 /* Validate all the parameters are present */
1675 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] ||
1676 !tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]) {
1677 hddLog(LOGE, FL("Parameters are not present."));
1678 return -EINVAL;
1679 }
1680
1681 channel_count = nla_get_u32(
1682 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT]);
1683 request_array_len = nla_len(
1684 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]);
1685 request_array = nla_data(
1686 tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]);
1687
1688 /* Initialize the callback context */
1689 init_completion(&context.completion_evt);
1690 context.adapter = adapter;
1691 context.magic = HDD_OCB_MAGIC;
1692
1693 request.vdev_id = adapter->sessionId;
1694 request.channel_count = channel_count;
1695 request.request_array_len = request_array_len;
1696 request.request_array = request_array;
1697
1698 /* Call the SME function. */
1699 rc = sme_dcc_get_stats(hdd_ctx->hHal, &context,
1700 hdd_dcc_get_stats_callback,
1701 &request);
1702 if (rc) {
1703 hddLog(LOGE, FL("Error calling SME function"));
1704 /* Need to convert from cdf_status to errno. */
1705 return -EINVAL;
1706 }
1707
1708 /* Wait for the function to complete. */
1709 rc = wait_for_completion_timeout(&context.completion_evt,
1710 msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD));
1711 if (rc == 0) {
1712 hddLog(LOGE, FL("Operation failed: %d"), rc);
1713 rc = -ETIMEDOUT;
1714 goto end;
1715 }
1716
1717 if (context.status) {
1718 hddLog(LOGE, FL("There was error: %d"), context.status);
1719 rc = context.status;
1720 goto end;
1721 }
1722
1723 if (!adapter->dcc_get_stats_resp) {
1724 hddLog(LOGE, FL("The response was NULL"));
1725 rc = -EINVAL;
1726 goto end;
1727 }
1728
1729 /* Allocate the buffer for the response. */
1730 nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(uint32_t) +
1731 adapter->dcc_get_stats_resp->channel_stats_array_len +
1732 NLMSG_HDRLEN);
1733 if (!nl_resp) {
1734 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
1735 rc = -ENOMEM;
1736 goto end;
1737 }
1738
1739 /* Populate the response. */
1740 rc = nla_put_u32(nl_resp,
1741 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT,
1742 adapter->dcc_get_stats_resp->num_channels);
1743 if (rc)
1744 goto end;
1745 rc = nla_put(nl_resp,
1746 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY,
1747 adapter->dcc_get_stats_resp->channel_stats_array_len,
1748 adapter->dcc_get_stats_resp->channel_stats_array);
1749 if (rc)
1750 goto end;
1751
1752 /* Send the response. */
1753 rc = cfg80211_vendor_cmd_reply(nl_resp);
1754 nl_resp = NULL;
1755 if (rc) {
1756 hddLog(LOGE, FL("cfg80211_vendor_cmd_reply failed: %d"), rc);
1757 goto end;
1758 }
1759
1760 /* fall through */
1761end:
1762 spin_lock(&hdd_context_lock);
1763 context.magic = 0;
1764 cdf_mem_free(adapter->dcc_get_stats_resp);
1765 adapter->dcc_get_stats_resp = NULL;
1766 spin_unlock(&hdd_context_lock);
1767 if (nl_resp)
1768 kfree_skb(nl_resp);
1769 return rc;
1770}
1771
1772/**
1773 * wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats
1774 * @wiphy: pointer to the wiphy
1775 * @wdev: pointer to the wdev
1776 * @data: The netlink data
1777 * @data_len: The length of the netlink data in bytes
1778 *
1779 * Return: 0 on success.
1780 */
1781int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy,
1782 struct wireless_dev *wdev,
1783 const void *data,
1784 int data_len)
1785{
1786 int ret;
1787
1788 cds_ssr_protect(__func__);
1789 ret = __wlan_hdd_cfg80211_dcc_get_stats(wiphy, wdev,
1790 data, data_len);
1791 cds_ssr_unprotect(__func__);
1792
1793 return ret;
1794}
1795
1796/**
1797 * __wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd
1798 * @wiphy: pointer to the wiphy
1799 * @wdev: pointer to the wdev
1800 * @data: The netlink data
1801 * @data_len: The length of the netlink data in bytes
1802 *
1803 * Return: 0 on success.
1804 */
1805static int __wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy,
1806 struct wireless_dev *wdev,
1807 const void *data,
1808 int data_len)
1809{
1810 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1811 struct net_device *dev = wdev->netdev;
1812 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1813 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX + 1];
1814
1815 ENTER();
1816
1817 if (wlan_hdd_validate_context(hdd_ctx)) {
1818 hddLog(LOGE, FL("HDD context is not valid"));
1819 return -EINVAL;
1820 }
1821
1822 if (adapter->device_mode != WLAN_HDD_OCB) {
1823 hddLog(LOGE, FL("Device not in OCB mode!"));
1824 return -EINVAL;
1825 }
1826
1827 if (!wma_is_vdev_up(adapter->sessionId)) {
1828 hddLog(LOGE, FL("The device has not been started"));
1829 return -EINVAL;
1830 }
1831
1832 /* Parse the netlink message */
1833 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX,
1834 data,
1835 data_len,
1836 qca_wlan_vendor_dcc_clear_stats)) {
1837 hddLog(LOGE, FL("Invalid ATTR"));
1838 return -EINVAL;
1839 }
1840
1841 /* Verify that the parameter is present */
1842 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP]) {
1843 hddLog(LOGE, FL("Parameters are not present."));
1844 return -EINVAL;
1845 }
1846
1847 /* Call the SME function */
1848 if (sme_dcc_clear_stats(hdd_ctx->hHal, adapter->sessionId,
1849 nla_get_u32(
1850 tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP])) !=
1851 CDF_STATUS_SUCCESS) {
1852 hddLog(LOGE, FL("Error calling SME function."));
1853 return -EINVAL;
1854 }
1855
1856 return 0;
1857}
1858
1859/**
1860 * wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd
1861 * @wiphy: pointer to the wiphy
1862 * @wdev: pointer to the wdev
1863 * @data: The netlink data
1864 * @data_len: The length of the netlink data in bytes
1865 *
1866 * Return: 0 on success.
1867 */
1868int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy,
1869 struct wireless_dev *wdev,
1870 const void *data,
1871 int data_len)
1872{
1873 int ret;
1874
1875 cds_ssr_protect(__func__);
1876 ret = __wlan_hdd_cfg80211_dcc_clear_stats(wiphy, wdev,
1877 data, data_len);
1878 cds_ssr_unprotect(__func__);
1879
1880 return ret;
1881}
1882
1883/**
1884 * hdd_dcc_update_ndl_callback() - Callback to update NDL command
1885 * @context_ptr: request context
1886 * @response_ptr: response data
1887 */
1888static void hdd_dcc_update_ndl_callback(void *context_ptr, void *response_ptr)
1889{
1890 struct hdd_ocb_ctxt *context = context_ptr;
1891 struct sir_dcc_update_ndl_response *response = response_ptr;
1892
1893 if (!context)
1894 return;
1895
1896 spin_lock(&hdd_context_lock);
1897 if (context->magic == HDD_OCB_MAGIC) {
1898 if (response) {
1899 context->adapter->dcc_update_ndl_resp = *response;
1900 context->status = 0;
1901 } else {
1902 context->status = -EINVAL;
1903 }
1904 complete(&context->completion_evt);
1905 }
1906 spin_unlock(&hdd_context_lock);
1907}
1908
1909/**
1910 * __wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd
1911 * @wiphy: pointer to the wiphy
1912 * @wdev: pointer to the wdev
1913 * @data: The netlink data
1914 * @data_len: The length of the netlink data in bytes
1915 *
1916 * Return: 0 on success.
1917 */
1918static int __wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy,
1919 struct wireless_dev *wdev,
1920 const void *data,
1921 int data_len)
1922{
1923 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1924 struct net_device *dev = wdev->netdev;
1925 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1926 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1];
1927 struct sir_dcc_update_ndl request;
1928 uint32_t channel_count;
1929 uint32_t ndl_channel_array_len;
1930 void *ndl_channel_array;
1931 uint32_t ndl_active_state_array_len;
1932 void *ndl_active_state_array;
1933 int rc = -EINVAL;
1934 struct hdd_ocb_ctxt context = {0};
1935
1936 ENTER();
1937
1938 if (wlan_hdd_validate_context(hdd_ctx)) {
1939 hddLog(LOGE, FL("HDD context is not valid"));
1940 goto end;
1941 }
1942
1943 if (adapter->device_mode != WLAN_HDD_OCB) {
1944 hddLog(LOGE, FL("Device not in OCB mode!"));
1945 goto end;
1946 }
1947
1948 if (!wma_is_vdev_up(adapter->sessionId)) {
1949 hddLog(LOGE, FL("The device has not been started"));
1950 return -EINVAL;
1951 }
1952
1953 /* Parse the netlink message */
1954 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX,
1955 data,
1956 data_len,
1957 qca_wlan_vendor_dcc_update_ndl)) {
1958 hddLog(LOGE, FL("Invalid ATTR"));
1959 goto end;
1960 }
1961
1962 /* Verify that the parameter is present */
1963 if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] ||
1964 !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] ||
1965 !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]) {
1966 hddLog(LOGE, FL("Parameters are not present."));
1967 return -EINVAL;
1968 }
1969
1970 channel_count = nla_get_u32(
1971 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT]);
1972 ndl_channel_array_len = nla_len(
1973 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]);
1974 ndl_channel_array = nla_data(
1975 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]);
1976 ndl_active_state_array_len = nla_len(
1977 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]);
1978 ndl_active_state_array = nla_data(
1979 tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]);
1980
1981 /* Initialize the callback context */
1982 init_completion(&context.completion_evt);
1983 context.adapter = adapter;
1984 context.magic = HDD_OCB_MAGIC;
1985
1986 /* Copy the parameters to the request structure. */
1987 request.vdev_id = adapter->sessionId;
1988 request.channel_count = channel_count;
1989 request.dcc_ndl_chan_list_len = ndl_channel_array_len;
1990 request.dcc_ndl_chan_list = ndl_channel_array;
1991 request.dcc_ndl_active_state_list_len = ndl_active_state_array_len;
1992 request.dcc_ndl_active_state_list = ndl_active_state_array;
1993
1994 /* Call the SME function */
1995 rc = sme_dcc_update_ndl(hdd_ctx->hHal, &context,
1996 hdd_dcc_update_ndl_callback,
1997 &request);
1998 if (rc) {
1999 hddLog(LOGE, FL("Error calling SME function."));
2000 /* Convert from cdf_status to errno */
2001 return -EINVAL;
2002 }
2003
2004 /* Wait for the function to complete. */
2005 rc = wait_for_completion_timeout(&context.completion_evt,
2006 msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD));
2007 if (rc == 0) {
2008 hddLog(LOGE, FL("Operation timed out"));
2009 rc = -ETIMEDOUT;
2010 goto end;
2011 }
2012 rc = 0;
2013
2014 if (context.status) {
2015 hddLog(LOGE, FL("Operation failed: %d"), context.status);
2016 rc = context.status;
2017 goto end;
2018 }
2019
2020 if (adapter->dcc_update_ndl_resp.status) {
2021 hddLog(LOGE, FL("Operation returned: %d"),
2022 adapter->dcc_update_ndl_resp.status);
2023 rc = -EINVAL;
2024 goto end;
2025 }
2026
2027 /* fall through */
2028end:
2029 spin_lock(&hdd_context_lock);
2030 context.magic = 0;
2031 spin_unlock(&hdd_context_lock);
2032 return rc;
2033}
2034
2035/**
2036 * wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd
2037 * @wiphy: pointer to the wiphy
2038 * @wdev: pointer to the wdev
2039 * @data: The netlink data
2040 * @data_len: The length of the netlink data in bytes
2041 *
2042 * Return: 0 on success.
2043 */
2044int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy,
2045 struct wireless_dev *wdev,
2046 const void *data,
2047 int data_len)
2048{
2049 int ret;
2050
2051 cds_ssr_protect(__func__);
2052 ret = __wlan_hdd_cfg80211_dcc_update_ndl(wiphy, wdev,
2053 data, data_len);
2054 cds_ssr_unprotect(__func__);
2055
2056 return ret;
2057}
2058
2059/**
2060 * wlan_hdd_dcc_stats_event_callback() - Callback to get stats event
2061 * @context_ptr: request context
2062 * @response_ptr: response data
2063 */
2064static void wlan_hdd_dcc_stats_event_callback(void *context_ptr,
2065 void *response_ptr)
2066{
2067 hdd_context_t *hdd_ctx = (hdd_context_t *)context_ptr;
2068 struct sir_dcc_get_stats_response *resp = response_ptr;
2069 struct sk_buff *vendor_event;
2070
2071 ENTER();
2072
2073 vendor_event =
2074 cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
2075 NULL, sizeof(uint32_t) + resp->channel_stats_array_len +
2076 NLMSG_HDRLEN,
2077 QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX,
2078 GFP_KERNEL);
2079
2080 if (!vendor_event) {
2081 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
2082 return;
2083 }
2084
2085 if (nla_put_u32(vendor_event,
2086 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT,
2087 resp->num_channels) ||
2088 nla_put(vendor_event,
2089 QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY,
2090 resp->channel_stats_array_len,
2091 resp->channel_stats_array)) {
2092 hddLog(LOGE, FL("nla put failed"));
2093 kfree_skb(vendor_event);
2094 return;
2095 }
2096
2097 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
2098}
2099
2100/**
2101 * wlan_hdd_dcc_register_for_dcc_stats_event() - Register for dcc stats events
2102 * @hdd_ctx: hdd context
2103 */
2104void wlan_hdd_dcc_register_for_dcc_stats_event(hdd_context_t *hdd_ctx)
2105{
2106 int rc;
2107
2108 rc = sme_register_for_dcc_stats_event(hdd_ctx->hHal, hdd_ctx,
2109 wlan_hdd_dcc_stats_event_callback);
2110 if (rc)
2111 hddLog(LOGE, FL("Register callback failed: %d"), rc);
2112}