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