xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-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_oemdata.c
22*5113495bSYour Name  *
23*5113495bSYour Name  *  Support for generic OEM Data Request handling
24*5113495bSYour Name  *
25*5113495bSYour Name  */
26*5113495bSYour Name 
27*5113495bSYour Name #if defined(FEATURE_OEM_DATA_SUPPORT) || defined(FEATURE_OEM_DATA)
28*5113495bSYour Name #include <linux/version.h>
29*5113495bSYour Name #include <linux/module.h>
30*5113495bSYour Name #include <linux/kernel.h>
31*5113495bSYour Name #include <linux/init.h>
32*5113495bSYour Name #include <linux/wireless.h>
33*5113495bSYour Name #include "osif_sync.h"
34*5113495bSYour Name #include <wlan_hdd_includes.h>
35*5113495bSYour Name #include <net/arp.h>
36*5113495bSYour Name #include "qwlan_version.h"
37*5113495bSYour Name #include "cds_utils.h"
38*5113495bSYour Name #include "wma.h"
39*5113495bSYour Name #include "sme_api.h"
40*5113495bSYour Name #include "wlan_nlink_srv.h"
41*5113495bSYour Name #include "wlan_hdd_oemdata.h"
42*5113495bSYour Name #include "wlan_osif_request_manager.h"
43*5113495bSYour Name #include "wlan_hdd_main.h"
44*5113495bSYour Name #include "wlan_hdd_sysfs.h"
45*5113495bSYour Name 
46*5113495bSYour Name #ifdef FEATURE_OEM_DATA_SUPPORT
47*5113495bSYour Name #ifdef CNSS_GENL
48*5113495bSYour Name #include <net/cnss_nl.h>
49*5113495bSYour Name #endif
50*5113495bSYour Name 
51*5113495bSYour Name static struct hdd_context *p_hdd_ctx;
52*5113495bSYour Name 
53*5113495bSYour Name /**
54*5113495bSYour Name  * populate_oem_data_cap() - populate oem capabilities
55*5113495bSYour Name  * @adapter: device adapter
56*5113495bSYour Name  * @data_cap: pointer to populate the capabilities
57*5113495bSYour Name  *
58*5113495bSYour Name  * Return: error code
59*5113495bSYour Name  */
populate_oem_data_cap(struct hdd_adapter * adapter,struct oem_data_cap * data_cap)60*5113495bSYour Name static int populate_oem_data_cap(struct hdd_adapter *adapter,
61*5113495bSYour Name 				 struct oem_data_cap *data_cap)
62*5113495bSYour Name {
63*5113495bSYour Name 	QDF_STATUS status;
64*5113495bSYour Name 	struct hdd_config *config;
65*5113495bSYour Name 	uint32_t num_chan, i;
66*5113495bSYour Name 	uint32_t *chan_freq_list;
67*5113495bSYour Name 	uint8_t band_capability;
68*5113495bSYour Name 	uint32_t band_bitmap;
69*5113495bSYour Name 	uint16_t neighbor_scan_min_chan_time;
70*5113495bSYour Name 	uint16_t neighbor_scan_max_chan_time;
71*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
72*5113495bSYour Name 
73*5113495bSYour Name 	config = hdd_ctx->config;
74*5113495bSYour Name 	if (!config) {
75*5113495bSYour Name 		hdd_err("HDD configuration is null");
76*5113495bSYour Name 		return -EINVAL;
77*5113495bSYour Name 	}
78*5113495bSYour Name 
79*5113495bSYour Name 	status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_bitmap);
80*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
81*5113495bSYour Name 		hdd_err("Failed to get MLME band capability");
82*5113495bSYour Name 		return -EIO;
83*5113495bSYour Name 	}
84*5113495bSYour Name 
85*5113495bSYour Name 	band_capability = wlan_reg_band_bitmap_to_band_info(band_bitmap);
86*5113495bSYour Name 
87*5113495bSYour Name 	chan_freq_list =
88*5113495bSYour Name 		qdf_mem_malloc(sizeof(uint32_t) * OEM_CAP_MAX_NUM_CHANNELS);
89*5113495bSYour Name 	if (!chan_freq_list)
90*5113495bSYour Name 		return -ENOMEM;
91*5113495bSYour Name 
92*5113495bSYour Name 	strlcpy(data_cap->oem_target_signature, OEM_TARGET_SIGNATURE,
93*5113495bSYour Name 		OEM_TARGET_SIGNATURE_LEN);
94*5113495bSYour Name 	data_cap->oem_target_type = hdd_ctx->target_type;
95*5113495bSYour Name 	data_cap->oem_fw_version = hdd_ctx->target_fw_version;
96*5113495bSYour Name 	data_cap->driver_version.major = QWLAN_VERSION_MAJOR;
97*5113495bSYour Name 	data_cap->driver_version.minor = QWLAN_VERSION_MINOR;
98*5113495bSYour Name 	data_cap->driver_version.patch = QWLAN_VERSION_PATCH;
99*5113495bSYour Name 	data_cap->driver_version.build = QWLAN_VERSION_BUILD;
100*5113495bSYour Name 	ucfg_mlme_get_neighbor_scan_max_chan_time(psoc,
101*5113495bSYour Name 						  &neighbor_scan_max_chan_time);
102*5113495bSYour Name 	ucfg_mlme_get_neighbor_scan_min_chan_time(psoc,
103*5113495bSYour Name 						  &neighbor_scan_min_chan_time);
104*5113495bSYour Name 	data_cap->allowed_dwell_time_min = neighbor_scan_min_chan_time;
105*5113495bSYour Name 	data_cap->allowed_dwell_time_max = neighbor_scan_max_chan_time;
106*5113495bSYour Name 	data_cap->curr_dwell_time_min =
107*5113495bSYour Name 		ucfg_cm_get_neighbor_scan_min_chan_time(
108*5113495bSYour Name 				hdd_ctx->psoc, adapter->deflink->vdev_id);
109*5113495bSYour Name 	data_cap->curr_dwell_time_max =
110*5113495bSYour Name 		ucfg_cm_get_neighbor_scan_max_chan_time(
111*5113495bSYour Name 				hdd_ctx->psoc, adapter->deflink->vdev_id);
112*5113495bSYour Name 	data_cap->supported_bands = band_capability;
113*5113495bSYour Name 
114*5113495bSYour Name 	/* request for max num of channels */
115*5113495bSYour Name 	num_chan = OEM_CAP_MAX_NUM_CHANNELS;
116*5113495bSYour Name 	status = sme_get_cfg_valid_channels(&chan_freq_list[0], &num_chan);
117*5113495bSYour Name 	if (QDF_STATUS_SUCCESS != status) {
118*5113495bSYour Name 		hdd_err("failed to get valid channel list, status: %d", status);
119*5113495bSYour Name 		qdf_mem_free(chan_freq_list);
120*5113495bSYour Name 		return -EINVAL;
121*5113495bSYour Name 	}
122*5113495bSYour Name 
123*5113495bSYour Name 	/* make sure num channels is not more than chan list array */
124*5113495bSYour Name 	if (num_chan > OEM_CAP_MAX_NUM_CHANNELS) {
125*5113495bSYour Name 		hdd_err("Num of channels-%d > length-%d of chan_freq_list",
126*5113495bSYour Name 			num_chan, OEM_CAP_MAX_NUM_CHANNELS);
127*5113495bSYour Name 		qdf_mem_free(chan_freq_list);
128*5113495bSYour Name 		return -ENOMEM;
129*5113495bSYour Name 	}
130*5113495bSYour Name 
131*5113495bSYour Name 	data_cap->num_channels = num_chan;
132*5113495bSYour Name 	for (i = 0; i < num_chan; i++) {
133*5113495bSYour Name 		data_cap->channel_list[i] =
134*5113495bSYour Name 			wlan_reg_freq_to_chan(hdd_ctx->pdev, chan_freq_list[i]);
135*5113495bSYour Name 	}
136*5113495bSYour Name 
137*5113495bSYour Name 	qdf_mem_free(chan_freq_list);
138*5113495bSYour Name 	return 0;
139*5113495bSYour Name }
140*5113495bSYour Name 
141*5113495bSYour Name /**
142*5113495bSYour Name  * iw_get_oem_data_cap() - Get OEM Data Capabilities
143*5113495bSYour Name  * @dev: net device upon which the request was received
144*5113495bSYour Name  * @info: ioctl request information
145*5113495bSYour Name  * @wrqu: ioctl request data
146*5113495bSYour Name  * @extra: ioctl data payload
147*5113495bSYour Name  *
148*5113495bSYour Name  * This function gets the capability information for OEM Data Request
149*5113495bSYour Name  * and Response.
150*5113495bSYour Name  *
151*5113495bSYour Name  * Return: 0 for success, negative errno value on failure
152*5113495bSYour Name  */
iw_get_oem_data_cap(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)153*5113495bSYour Name int iw_get_oem_data_cap(struct net_device *dev,
154*5113495bSYour Name 			struct iw_request_info *info,
155*5113495bSYour Name 			union iwreq_data *wrqu, char *extra)
156*5113495bSYour Name {
157*5113495bSYour Name 	struct oem_data_cap *oem_data_cap = (void *)extra;
158*5113495bSYour Name 	struct hdd_adapter *adapter = netdev_priv(dev);
159*5113495bSYour Name 	struct hdd_context *hdd_ctx;
160*5113495bSYour Name 	int errno;
161*5113495bSYour Name 
162*5113495bSYour Name 	hdd_enter();
163*5113495bSYour Name 
164*5113495bSYour Name 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
165*5113495bSYour Name 	errno = wlan_hdd_validate_context(hdd_ctx);
166*5113495bSYour Name 	if (errno)
167*5113495bSYour Name 		return errno;
168*5113495bSYour Name 
169*5113495bSYour Name 	qdf_mem_zero(oem_data_cap, sizeof(*oem_data_cap));
170*5113495bSYour Name 	errno = populate_oem_data_cap(adapter, oem_data_cap);
171*5113495bSYour Name 	if (errno) {
172*5113495bSYour Name 		hdd_err("Failed to populate oem data capabilities");
173*5113495bSYour Name 		return errno;
174*5113495bSYour Name 	}
175*5113495bSYour Name 
176*5113495bSYour Name 	hdd_exit();
177*5113495bSYour Name 	return 0;
178*5113495bSYour Name }
179*5113495bSYour Name 
180*5113495bSYour Name /**
181*5113495bSYour Name  * send_oem_reg_rsp_nlink_msg() - send oem registration response
182*5113495bSYour Name  *
183*5113495bSYour Name  * This function sends oem message to registered application process
184*5113495bSYour Name  *
185*5113495bSYour Name  * Return:  none
186*5113495bSYour Name  */
send_oem_reg_rsp_nlink_msg(void)187*5113495bSYour Name static void send_oem_reg_rsp_nlink_msg(void)
188*5113495bSYour Name {
189*5113495bSYour Name 	struct sk_buff *skb;
190*5113495bSYour Name 	struct nlmsghdr *nlh;
191*5113495bSYour Name 	tAniMsgHdr *ani_hdr;
192*5113495bSYour Name 	uint8_t *buf;
193*5113495bSYour Name 	uint8_t *num_interfaces;
194*5113495bSYour Name 	uint8_t *device_mode;
195*5113495bSYour Name 	uint8_t *vdev_id;
196*5113495bSYour Name 	struct hdd_adapter *adapter, *next_adapter = NULL;
197*5113495bSYour Name 	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_SEND_OEM_REG_RSP_NLINK_MSG;
198*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
199*5113495bSYour Name 
200*5113495bSYour Name 	/* OEM msg is always to a specific process & cannot be a broadcast */
201*5113495bSYour Name 	if (p_hdd_ctx->oem_pid == 0) {
202*5113495bSYour Name 		hdd_err("invalid dest pid");
203*5113495bSYour Name 		return;
204*5113495bSYour Name 	}
205*5113495bSYour Name 
206*5113495bSYour Name 	skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
207*5113495bSYour Name 	if (!skb)
208*5113495bSYour Name 		return;
209*5113495bSYour Name 
210*5113495bSYour Name 	nlh = (struct nlmsghdr *)skb->data;
211*5113495bSYour Name 	nlh->nlmsg_pid = 0;     /* from kernel */
212*5113495bSYour Name 	nlh->nlmsg_flags = 0;
213*5113495bSYour Name 	nlh->nlmsg_seq = 0;
214*5113495bSYour Name 	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
215*5113495bSYour Name 	ani_hdr = NLMSG_DATA(nlh);
216*5113495bSYour Name 	ani_hdr->type = ANI_MSG_APP_REG_RSP;
217*5113495bSYour Name 
218*5113495bSYour Name 	/* Fill message body:
219*5113495bSYour Name 	 *   First byte will be number of interfaces, followed by
220*5113495bSYour Name 	 *   two bytes for each interfaces
221*5113495bSYour Name 	 *     - one byte for device mode
222*5113495bSYour Name 	 *     - one byte for vdev id
223*5113495bSYour Name 	 */
224*5113495bSYour Name 	buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
225*5113495bSYour Name 	num_interfaces = buf++;
226*5113495bSYour Name 	*num_interfaces = 0;
227*5113495bSYour Name 
228*5113495bSYour Name 	/* Iterate through each adapter and fill device mode and vdev id */
229*5113495bSYour Name 	hdd_for_each_adapter_dev_held_safe(p_hdd_ctx, adapter, next_adapter,
230*5113495bSYour Name 					   dbgid) {
231*5113495bSYour Name 		hdd_adapter_for_each_active_link_info(adapter, link_info) {
232*5113495bSYour Name 			device_mode = buf++;
233*5113495bSYour Name 			vdev_id = buf++;
234*5113495bSYour Name 			*device_mode = adapter->device_mode;
235*5113495bSYour Name 			*vdev_id = link_info->vdev_id;
236*5113495bSYour Name 			(*num_interfaces)++;
237*5113495bSYour Name 			hdd_debug("num_interfaces: %d, device_mode: %d, vdev_id: %d",
238*5113495bSYour Name 				  *num_interfaces, *device_mode, *vdev_id);
239*5113495bSYour Name 		}
240*5113495bSYour Name 		hdd_adapter_dev_put_debug(adapter, dbgid);
241*5113495bSYour Name 	}
242*5113495bSYour Name 
243*5113495bSYour Name 	ani_hdr->length =
244*5113495bSYour Name 		sizeof(uint8_t) + (*num_interfaces) * 2 * sizeof(uint8_t);
245*5113495bSYour Name 	nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
246*5113495bSYour Name 
247*5113495bSYour Name 	skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
248*5113495bSYour Name 
249*5113495bSYour Name 	hdd_debug("sending App Reg Response length: %d to pid: %d",
250*5113495bSYour Name 		   ani_hdr->length, p_hdd_ctx->oem_pid);
251*5113495bSYour Name 
252*5113495bSYour Name 	(void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
253*5113495bSYour Name }
254*5113495bSYour Name 
255*5113495bSYour Name /**
256*5113495bSYour Name  * send_oem_err_rsp_nlink_msg() - send oem error response
257*5113495bSYour Name  * @app_pid: PID of oem application process
258*5113495bSYour Name  * @error_code: response error code
259*5113495bSYour Name  *
260*5113495bSYour Name  * This function sends error response to oem app
261*5113495bSYour Name  *
262*5113495bSYour Name  * Return: none
263*5113495bSYour Name  */
send_oem_err_rsp_nlink_msg(int32_t app_pid,uint8_t error_code)264*5113495bSYour Name static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code)
265*5113495bSYour Name {
266*5113495bSYour Name 	struct sk_buff *skb;
267*5113495bSYour Name 	struct nlmsghdr *nlh;
268*5113495bSYour Name 	tAniMsgHdr *ani_hdr;
269*5113495bSYour Name 	uint8_t *buf;
270*5113495bSYour Name 
271*5113495bSYour Name 	skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
272*5113495bSYour Name 	if (!skb)
273*5113495bSYour Name 		return;
274*5113495bSYour Name 
275*5113495bSYour Name 	nlh = (struct nlmsghdr *)skb->data;
276*5113495bSYour Name 	nlh->nlmsg_pid = 0;     /* from kernel */
277*5113495bSYour Name 	nlh->nlmsg_flags = 0;
278*5113495bSYour Name 	nlh->nlmsg_seq = 0;
279*5113495bSYour Name 	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
280*5113495bSYour Name 	ani_hdr = NLMSG_DATA(nlh);
281*5113495bSYour Name 	ani_hdr->type = ANI_MSG_OEM_ERROR;
282*5113495bSYour Name 	ani_hdr->length = sizeof(uint8_t);
283*5113495bSYour Name 	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length);
284*5113495bSYour Name 
285*5113495bSYour Name 	/* message body will contain one byte of error code */
286*5113495bSYour Name 	buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
287*5113495bSYour Name 	*buf = error_code;
288*5113495bSYour Name 
289*5113495bSYour Name 	skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length));
290*5113495bSYour Name 
291*5113495bSYour Name 	hdd_debug("sending oem error response to pid: %d", app_pid);
292*5113495bSYour Name 
293*5113495bSYour Name 	(void)nl_srv_ucast_oem(skb, app_pid, MSG_DONTWAIT);
294*5113495bSYour Name }
295*5113495bSYour Name 
296*5113495bSYour Name /**
297*5113495bSYour Name  * hdd_send_oem_data_rsp_msg() - send oem data response
298*5113495bSYour Name  * @oem_data_rsp: the actual OEM Data Response message
299*5113495bSYour Name  *
300*5113495bSYour Name  * This function sends an OEM Data Response message to a registered
301*5113495bSYour Name  * application process over the netlink socket.
302*5113495bSYour Name  *
303*5113495bSYour Name  * Return: 0 for success, non zero for failure
304*5113495bSYour Name  */
hdd_send_oem_data_rsp_msg(struct oem_data_rsp * oem_data_rsp)305*5113495bSYour Name void hdd_send_oem_data_rsp_msg(struct oem_data_rsp *oem_data_rsp)
306*5113495bSYour Name {
307*5113495bSYour Name 	struct sk_buff *skb;
308*5113495bSYour Name 	struct nlmsghdr *nlh;
309*5113495bSYour Name 	tAniMsgHdr *ani_hdr;
310*5113495bSYour Name 	uint8_t *oem_data;
311*5113495bSYour Name 
312*5113495bSYour Name 	/*
313*5113495bSYour Name 	 * OEM message is always to a specific process and cannot be a broadcast
314*5113495bSYour Name 	 */
315*5113495bSYour Name 	if (p_hdd_ctx->oem_pid == 0) {
316*5113495bSYour Name 		hdd_err("invalid dest pid");
317*5113495bSYour Name 		return;
318*5113495bSYour Name 	}
319*5113495bSYour Name 
320*5113495bSYour Name 	if (oem_data_rsp->rsp_len > OEM_DATA_RSP_SIZE) {
321*5113495bSYour Name 		hdd_err("invalid length of Oem Data response");
322*5113495bSYour Name 		return;
323*5113495bSYour Name 	}
324*5113495bSYour Name 
325*5113495bSYour Name 	skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + OEM_DATA_RSP_SIZE),
326*5113495bSYour Name 			GFP_KERNEL);
327*5113495bSYour Name 	if (!skb)
328*5113495bSYour Name 		return;
329*5113495bSYour Name 
330*5113495bSYour Name 	nlh = (struct nlmsghdr *)skb->data;
331*5113495bSYour Name 	nlh->nlmsg_pid = 0;     /* from kernel */
332*5113495bSYour Name 	nlh->nlmsg_flags = 0;
333*5113495bSYour Name 	nlh->nlmsg_seq = 0;
334*5113495bSYour Name 	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
335*5113495bSYour Name 	ani_hdr = NLMSG_DATA(nlh);
336*5113495bSYour Name 	ani_hdr->type = ANI_MSG_OEM_DATA_RSP;
337*5113495bSYour Name 
338*5113495bSYour Name 	ani_hdr->length = oem_data_rsp->rsp_len;
339*5113495bSYour Name 	nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
340*5113495bSYour Name 	oem_data = (uint8_t *) ((char *)ani_hdr + sizeof(tAniMsgHdr));
341*5113495bSYour Name 	qdf_mem_copy(oem_data, oem_data_rsp->data, oem_data_rsp->rsp_len);
342*5113495bSYour Name 
343*5113495bSYour Name 	skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
344*5113495bSYour Name 
345*5113495bSYour Name 	hdd_debug("sending Oem Data Response of len : %d to pid: %d",
346*5113495bSYour Name 		   oem_data_rsp->rsp_len, p_hdd_ctx->oem_pid);
347*5113495bSYour Name 
348*5113495bSYour Name 	(void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
349*5113495bSYour Name }
350*5113495bSYour Name 
351*5113495bSYour Name /**
352*5113495bSYour Name  * oem_process_data_req_msg() - process oem data request
353*5113495bSYour Name  * @oem_data_len: Length to OEM Data buffer
354*5113495bSYour Name  * @oem_data: Pointer to OEM Data buffer
355*5113495bSYour Name  *
356*5113495bSYour Name  * This function sends oem message to SME
357*5113495bSYour Name  *
358*5113495bSYour Name  * Return: QDF_STATUS enumeration
359*5113495bSYour Name  */
oem_process_data_req_msg(int oem_data_len,char * oem_data)360*5113495bSYour Name static QDF_STATUS oem_process_data_req_msg(int oem_data_len, char *oem_data)
361*5113495bSYour Name {
362*5113495bSYour Name 	struct oem_data_req oem_data_req;
363*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
364*5113495bSYour Name 
365*5113495bSYour Name 	/* for now, STA interface only */
366*5113495bSYour Name 	if (!hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE) &&
367*5113495bSYour Name 	    !hdd_get_adapter(p_hdd_ctx, QDF_SAP_MODE)) {
368*5113495bSYour Name 		hdd_err("No adapter for STA or SAP mode");
369*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
370*5113495bSYour Name 	}
371*5113495bSYour Name 
372*5113495bSYour Name 	if (!oem_data) {
373*5113495bSYour Name 		hdd_err("oem_data is null");
374*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
375*5113495bSYour Name 	}
376*5113495bSYour Name 
377*5113495bSYour Name 	qdf_mem_zero(&oem_data_req, sizeof(oem_data_req));
378*5113495bSYour Name 
379*5113495bSYour Name 	oem_data_req.data = qdf_mem_malloc(oem_data_len);
380*5113495bSYour Name 	if (!oem_data_req.data)
381*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
382*5113495bSYour Name 
383*5113495bSYour Name 	oem_data_req.data_len = oem_data_len;
384*5113495bSYour Name 	qdf_mem_copy(oem_data_req.data, oem_data, oem_data_len);
385*5113495bSYour Name 
386*5113495bSYour Name 	status = sme_oem_req_cmd(p_hdd_ctx->mac_handle, &oem_data_req);
387*5113495bSYour Name 
388*5113495bSYour Name 	qdf_mem_free(oem_data_req.data);
389*5113495bSYour Name 	oem_data_req.data = NULL;
390*5113495bSYour Name 
391*5113495bSYour Name 	return status;
392*5113495bSYour Name }
393*5113495bSYour Name 
hdd_update_channel_bw_info(struct hdd_context * hdd_ctx,uint32_t chan_freq,void * chan_info)394*5113495bSYour Name void hdd_update_channel_bw_info(struct hdd_context *hdd_ctx,
395*5113495bSYour Name 				uint32_t chan_freq, void *chan_info)
396*5113495bSYour Name {
397*5113495bSYour Name 	struct ch_params ch_params = {0};
398*5113495bSYour Name 	enum wlan_phymode phy_mode;
399*5113495bSYour Name 	uint16_t fw_phy_mode;
400*5113495bSYour Name 	uint32_t wni_dot11_mode;
401*5113495bSYour Name 	struct hdd_channel_info *hdd_chan_info = chan_info;
402*5113495bSYour Name 
403*5113495bSYour Name 	wni_dot11_mode = sme_get_wni_dot11_mode(hdd_ctx->mac_handle);
404*5113495bSYour Name 
405*5113495bSYour Name 	/* Passing CH_WIDTH_MAX will give the max bandwidth supported */
406*5113495bSYour Name 	ch_params.ch_width = CH_WIDTH_MAX;
407*5113495bSYour Name 
408*5113495bSYour Name 	wlan_reg_set_channel_params_for_pwrmode(
409*5113495bSYour Name 		hdd_ctx->pdev, chan_freq, 0, &ch_params, REG_CURRENT_PWR_MODE);
410*5113495bSYour Name 	if (ch_params.center_freq_seg0)
411*5113495bSYour Name 		hdd_chan_info->band_center_freq1 =
412*5113495bSYour Name 			cds_chan_to_freq(ch_params.center_freq_seg0);
413*5113495bSYour Name 
414*5113495bSYour Name 	if (ch_params.ch_width < CH_WIDTH_INVALID) {
415*5113495bSYour Name 		phy_mode = wma_chan_phy_mode(chan_freq, ch_params.ch_width,
416*5113495bSYour Name 					     wni_dot11_mode);
417*5113495bSYour Name 	}
418*5113495bSYour Name 	else
419*5113495bSYour Name 		/*
420*5113495bSYour Name 		 * If channel width is CH_WIDTH_INVALID, It mean channel is
421*5113495bSYour Name 		 * invalid and should not have been received in channel info
422*5113495bSYour Name 		 * req. Set invalid phymode in this case.
423*5113495bSYour Name 		 */
424*5113495bSYour Name 		phy_mode = WLAN_PHYMODE_AUTO;
425*5113495bSYour Name 
426*5113495bSYour Name 	fw_phy_mode = wmi_host_to_fw_phymode(phy_mode);
427*5113495bSYour Name 
428*5113495bSYour Name 	hdd_debug("chan %d dot11_mode %d ch_width %d sec offset %d freq_seg0 %d phy_mode %d fw_phy_mode %d",
429*5113495bSYour Name 		  chan_freq, wni_dot11_mode, ch_params.ch_width,
430*5113495bSYour Name 		  ch_params.sec_ch_offset,
431*5113495bSYour Name 		  hdd_chan_info->band_center_freq1, phy_mode, fw_phy_mode);
432*5113495bSYour Name 
433*5113495bSYour Name 	WMI_SET_CHANNEL_MODE(hdd_chan_info, fw_phy_mode);
434*5113495bSYour Name }
435*5113495bSYour Name 
436*5113495bSYour Name /**
437*5113495bSYour Name  * oem_process_channel_info_req_msg() - process oem channel_info request
438*5113495bSYour Name  * @numOfChannels: number of channels
439*5113495bSYour Name  * @chanList: list of channel information
440*5113495bSYour Name  *
441*5113495bSYour Name  * This function responds with channel info to oem process
442*5113495bSYour Name  *
443*5113495bSYour Name  * Return: 0 for success, non zero for failure
444*5113495bSYour Name  */
oem_process_channel_info_req_msg(int numOfChannels,char * chanList)445*5113495bSYour Name static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList)
446*5113495bSYour Name {
447*5113495bSYour Name 	struct sk_buff *skb;
448*5113495bSYour Name 	struct nlmsghdr *nlh;
449*5113495bSYour Name 	tAniMsgHdr *ani_hdr;
450*5113495bSYour Name 	struct hdd_channel_info *pHddChanInfo;
451*5113495bSYour Name 	struct hdd_channel_info hddChanInfo;
452*5113495bSYour Name 	uint32_t reg_info_1;
453*5113495bSYour Name 	uint32_t reg_info_2;
454*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
455*5113495bSYour Name 	int i;
456*5113495bSYour Name 	uint8_t *buf;
457*5113495bSYour Name 	uint32_t chan_freq;
458*5113495bSYour Name 
459*5113495bSYour Name 	/* OEM msg is always to a specific process and cannot be a broadcast */
460*5113495bSYour Name 	if (p_hdd_ctx->oem_pid == 0) {
461*5113495bSYour Name 		hdd_err("invalid dest pid");
462*5113495bSYour Name 		return -EPERM;
463*5113495bSYour Name 	}
464*5113495bSYour Name 
465*5113495bSYour Name 	skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) +
466*5113495bSYour Name 				    numOfChannels * sizeof(*pHddChanInfo)),
467*5113495bSYour Name 			GFP_KERNEL);
468*5113495bSYour Name 	if (!skb)
469*5113495bSYour Name 		return -ENOMEM;
470*5113495bSYour Name 
471*5113495bSYour Name 	nlh = (struct nlmsghdr *)skb->data;
472*5113495bSYour Name 	nlh->nlmsg_pid = 0;     /* from kernel */
473*5113495bSYour Name 	nlh->nlmsg_flags = 0;
474*5113495bSYour Name 	nlh->nlmsg_seq = 0;
475*5113495bSYour Name 	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
476*5113495bSYour Name 	ani_hdr = NLMSG_DATA(nlh);
477*5113495bSYour Name 	ani_hdr->type = ANI_MSG_CHANNEL_INFO_RSP;
478*5113495bSYour Name 
479*5113495bSYour Name 	ani_hdr->length =
480*5113495bSYour Name 		sizeof(uint8_t) + numOfChannels * sizeof(*pHddChanInfo);
481*5113495bSYour Name 	nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
482*5113495bSYour Name 
483*5113495bSYour Name 	/* First byte of message body will have num of channels */
484*5113495bSYour Name 	buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
485*5113495bSYour Name 	*buf++ = numOfChannels;
486*5113495bSYour Name 
487*5113495bSYour Name 	/* Next follows channel info struct for each channel id.
488*5113495bSYour Name 	 * If chan id is wrong or SME returns failure for a channel
489*5113495bSYour Name 	 * then fill in 0 in channel info for that particular channel
490*5113495bSYour Name 	 */
491*5113495bSYour Name 	for (i = 0; i < numOfChannels; i++) {
492*5113495bSYour Name 		pHddChanInfo = (struct hdd_channel_info *) ((char *)buf +
493*5113495bSYour Name 						    i *
494*5113495bSYour Name 						    sizeof(*pHddChanInfo));
495*5113495bSYour Name 
496*5113495bSYour Name 		chan_freq = wlan_reg_legacy_chan_to_freq(
497*5113495bSYour Name 				p_hdd_ctx->pdev, chanList[i]);
498*5113495bSYour Name 		status = sme_get_reg_info(p_hdd_ctx->mac_handle, chan_freq,
499*5113495bSYour Name 					  &reg_info_1, &reg_info_2);
500*5113495bSYour Name 		if (QDF_STATUS_SUCCESS == status) {
501*5113495bSYour Name 			/* copy into hdd chan info struct */
502*5113495bSYour Name 			hddChanInfo.reserved0 = 0;
503*5113495bSYour Name 			hddChanInfo.mhz = chan_freq;
504*5113495bSYour Name 			hddChanInfo.band_center_freq1 = hddChanInfo.mhz;
505*5113495bSYour Name 			hddChanInfo.band_center_freq2 = 0;
506*5113495bSYour Name 
507*5113495bSYour Name 			hddChanInfo.info = 0;
508*5113495bSYour Name 			if (CHANNEL_STATE_DFS ==
509*5113495bSYour Name 			    wlan_reg_get_channel_state_for_pwrmode(
510*5113495bSYour Name 						p_hdd_ctx->pdev, chan_freq,
511*5113495bSYour Name 						REG_CURRENT_PWR_MODE))
512*5113495bSYour Name 				WMI_SET_CHANNEL_FLAG(&hddChanInfo,
513*5113495bSYour Name 						     WMI_CHAN_FLAG_DFS);
514*5113495bSYour Name 
515*5113495bSYour Name 			hdd_update_channel_bw_info(p_hdd_ctx,
516*5113495bSYour Name 						chan_freq, &hddChanInfo);
517*5113495bSYour Name 			hddChanInfo.reg_info_1 = reg_info_1;
518*5113495bSYour Name 			hddChanInfo.reg_info_2 = reg_info_2;
519*5113495bSYour Name 		} else {
520*5113495bSYour Name 			/* channel info is not returned, fill in zeros in
521*5113495bSYour Name 			 * channel info struct
522*5113495bSYour Name 			 */
523*5113495bSYour Name 			hdd_debug("sme_get_reg_info failed for chan: %d, fill 0s",
524*5113495bSYour Name 				   chan_freq);
525*5113495bSYour Name 			hddChanInfo.reserved0 = 0;
526*5113495bSYour Name 			hddChanInfo.mhz = chan_freq;
527*5113495bSYour Name 			hddChanInfo.band_center_freq1 = 0;
528*5113495bSYour Name 			hddChanInfo.band_center_freq2 = 0;
529*5113495bSYour Name 			hddChanInfo.info = 0;
530*5113495bSYour Name 			hddChanInfo.reg_info_1 = 0;
531*5113495bSYour Name 			hddChanInfo.reg_info_2 = 0;
532*5113495bSYour Name 		}
533*5113495bSYour Name 		qdf_mem_copy(pHddChanInfo, &hddChanInfo,
534*5113495bSYour Name 			     sizeof(*pHddChanInfo));
535*5113495bSYour Name 	}
536*5113495bSYour Name 
537*5113495bSYour Name 	skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
538*5113495bSYour Name 
539*5113495bSYour Name 	hdd_debug("sending channel info resp for num channels (%d) to pid (%d)",
540*5113495bSYour Name 		   numOfChannels, p_hdd_ctx->oem_pid);
541*5113495bSYour Name 
542*5113495bSYour Name 	(void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
543*5113495bSYour Name 
544*5113495bSYour Name 	return 0;
545*5113495bSYour Name }
546*5113495bSYour Name 
547*5113495bSYour Name /**
548*5113495bSYour Name  * oem_process_set_cap_req_msg() - process oem set capability request
549*5113495bSYour Name  * @oem_cap_len: Length of OEM capability
550*5113495bSYour Name  * @oem_cap: Pointer to OEM capability buffer
551*5113495bSYour Name  * @app_pid: process ID, to which rsp message is to be sent
552*5113495bSYour Name  *
553*5113495bSYour Name  * This function sends oem message to SME
554*5113495bSYour Name  *
555*5113495bSYour Name  * Return: error code
556*5113495bSYour Name  */
oem_process_set_cap_req_msg(int oem_cap_len,char * oem_cap,int32_t app_pid)557*5113495bSYour Name static int oem_process_set_cap_req_msg(int oem_cap_len,
558*5113495bSYour Name 				       char *oem_cap, int32_t app_pid)
559*5113495bSYour Name {
560*5113495bSYour Name 	QDF_STATUS status;
561*5113495bSYour Name 	int error_code;
562*5113495bSYour Name 	struct sk_buff *skb;
563*5113495bSYour Name 	struct nlmsghdr *nlh;
564*5113495bSYour Name 	tAniMsgHdr *ani_hdr;
565*5113495bSYour Name 	uint8_t *buf;
566*5113495bSYour Name 
567*5113495bSYour Name 	if (!oem_cap) {
568*5113495bSYour Name 		hdd_err("oem_cap is null");
569*5113495bSYour Name 		return -EINVAL;
570*5113495bSYour Name 	}
571*5113495bSYour Name 
572*5113495bSYour Name 	status = sme_oem_update_capability(p_hdd_ctx->mac_handle,
573*5113495bSYour Name 					(struct sme_oem_capability *)oem_cap);
574*5113495bSYour Name 	if (!QDF_IS_STATUS_SUCCESS(status))
575*5113495bSYour Name 		hdd_err("error updating rm capability, status: %d", status);
576*5113495bSYour Name 	error_code = qdf_status_to_os_return(status);
577*5113495bSYour Name 
578*5113495bSYour Name 	skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
579*5113495bSYour Name 	if (!skb)
580*5113495bSYour Name 		return -ENOMEM;
581*5113495bSYour Name 
582*5113495bSYour Name 	nlh = (struct nlmsghdr *)skb->data;
583*5113495bSYour Name 	nlh->nlmsg_pid = 0;     /* from kernel */
584*5113495bSYour Name 	nlh->nlmsg_flags = 0;
585*5113495bSYour Name 	nlh->nlmsg_seq = 0;
586*5113495bSYour Name 	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
587*5113495bSYour Name 	ani_hdr = NLMSG_DATA(nlh);
588*5113495bSYour Name 	ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP;
589*5113495bSYour Name 	/* 64 bit alignment */
590*5113495bSYour Name 	ani_hdr->length = sizeof(error_code);
591*5113495bSYour Name 	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length);
592*5113495bSYour Name 
593*5113495bSYour Name 	/* message body will contain only status code */
594*5113495bSYour Name 	buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
595*5113495bSYour Name 	qdf_mem_copy(buf, &error_code, ani_hdr->length);
596*5113495bSYour Name 
597*5113495bSYour Name 	skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length));
598*5113495bSYour Name 
599*5113495bSYour Name 	hdd_debug("sending oem response to pid %d", app_pid);
600*5113495bSYour Name 
601*5113495bSYour Name 	(void)nl_srv_ucast_oem(skb, app_pid, MSG_DONTWAIT);
602*5113495bSYour Name 
603*5113495bSYour Name 	return error_code;
604*5113495bSYour Name }
605*5113495bSYour Name 
606*5113495bSYour Name /**
607*5113495bSYour Name  * oem_process_get_cap_req_msg() - process oem get capability request
608*5113495bSYour Name  *
609*5113495bSYour Name  * This function process the get capability request from OEM and responds
610*5113495bSYour Name  * with the capability.
611*5113495bSYour Name  *
612*5113495bSYour Name  * Return: error code
613*5113495bSYour Name  */
oem_process_get_cap_req_msg(void)614*5113495bSYour Name static int oem_process_get_cap_req_msg(void)
615*5113495bSYour Name {
616*5113495bSYour Name 	int error_code;
617*5113495bSYour Name 	struct oem_get_capability_rsp *cap_rsp;
618*5113495bSYour Name 	struct oem_data_cap data_cap = { {0} };
619*5113495bSYour Name 	struct sme_oem_capability oem_cap;
620*5113495bSYour Name 	struct hdd_adapter *adapter;
621*5113495bSYour Name 	struct sk_buff *skb;
622*5113495bSYour Name 	struct nlmsghdr *nlh;
623*5113495bSYour Name 	tAniMsgHdr *ani_hdr;
624*5113495bSYour Name 	uint8_t *buf;
625*5113495bSYour Name 
626*5113495bSYour Name 	/* for now, STA interface only */
627*5113495bSYour Name 	adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE);
628*5113495bSYour Name 	if (!adapter) {
629*5113495bSYour Name 		hdd_err("No adapter for STA mode");
630*5113495bSYour Name 		return -EINVAL;
631*5113495bSYour Name 	}
632*5113495bSYour Name 
633*5113495bSYour Name 	error_code = populate_oem_data_cap(adapter, &data_cap);
634*5113495bSYour Name 	if (0 != error_code)
635*5113495bSYour Name 		return error_code;
636*5113495bSYour Name 
637*5113495bSYour Name 	skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)),
638*5113495bSYour Name 			GFP_KERNEL);
639*5113495bSYour Name 	if (!skb)
640*5113495bSYour Name 		return -ENOMEM;
641*5113495bSYour Name 
642*5113495bSYour Name 	nlh = (struct nlmsghdr *)skb->data;
643*5113495bSYour Name 	nlh->nlmsg_pid = 0;     /* from kernel */
644*5113495bSYour Name 	nlh->nlmsg_flags = 0;
645*5113495bSYour Name 	nlh->nlmsg_seq = 0;
646*5113495bSYour Name 	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
647*5113495bSYour Name 	ani_hdr = NLMSG_DATA(nlh);
648*5113495bSYour Name 	ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP;
649*5113495bSYour Name 
650*5113495bSYour Name 	ani_hdr->length = sizeof(*cap_rsp);
651*5113495bSYour Name 	nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
652*5113495bSYour Name 
653*5113495bSYour Name 	buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
654*5113495bSYour Name 	qdf_mem_copy(buf, &data_cap, sizeof(data_cap));
655*5113495bSYour Name 
656*5113495bSYour Name 	buf = (char *) buf +  sizeof(data_cap);
657*5113495bSYour Name 	qdf_mem_zero(&oem_cap, sizeof(oem_cap));
658*5113495bSYour Name 	sme_oem_get_capability(p_hdd_ctx->mac_handle, &oem_cap);
659*5113495bSYour Name 	qdf_mem_copy(buf, &oem_cap, sizeof(oem_cap));
660*5113495bSYour Name 
661*5113495bSYour Name 	skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
662*5113495bSYour Name 	hdd_info("send rsp to oem-pid:%d for get_capability",
663*5113495bSYour Name 		 p_hdd_ctx->oem_pid);
664*5113495bSYour Name 
665*5113495bSYour Name 	(void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
666*5113495bSYour Name 	return 0;
667*5113495bSYour Name }
668*5113495bSYour Name 
hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr * peer_mac,uint8_t peer_status,uint8_t peer_capability,uint8_t vdev_id,struct oem_channel_info * chan_info,enum QDF_OPMODE dev_mode)669*5113495bSYour Name void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peer_mac,
670*5113495bSYour Name 					 uint8_t peer_status,
671*5113495bSYour Name 					 uint8_t peer_capability,
672*5113495bSYour Name 					 uint8_t vdev_id,
673*5113495bSYour Name 					 struct oem_channel_info *chan_info,
674*5113495bSYour Name 					 enum QDF_OPMODE dev_mode)
675*5113495bSYour Name {
676*5113495bSYour Name 	struct sk_buff *skb;
677*5113495bSYour Name 	struct nlmsghdr *nlh;
678*5113495bSYour Name 	tAniMsgHdr *ani_hdr;
679*5113495bSYour Name 	struct peer_status_info *peer_info;
680*5113495bSYour Name 
681*5113495bSYour Name 	if (!p_hdd_ctx) {
682*5113495bSYour Name 		hdd_err("HDD Ctx is null");
683*5113495bSYour Name 		return;
684*5113495bSYour Name 	}
685*5113495bSYour Name 
686*5113495bSYour Name 	/* check if oem app has registered and pid is valid */
687*5113495bSYour Name 	if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) {
688*5113495bSYour Name 		hdd_info("OEM app is not registered(%d) or pid is invalid(%d)",
689*5113495bSYour Name 			 p_hdd_ctx->oem_app_registered,
690*5113495bSYour Name 			 p_hdd_ctx->oem_pid);
691*5113495bSYour Name 		return;
692*5113495bSYour Name 	}
693*5113495bSYour Name 
694*5113495bSYour Name 	skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) +
695*5113495bSYour Name 				    sizeof(*peer_info)),
696*5113495bSYour Name 			GFP_KERNEL);
697*5113495bSYour Name 	if (!skb)
698*5113495bSYour Name 		return;
699*5113495bSYour Name 
700*5113495bSYour Name 	nlh = (struct nlmsghdr *)skb->data;
701*5113495bSYour Name 	nlh->nlmsg_pid = 0;     /* from kernel */
702*5113495bSYour Name 	nlh->nlmsg_flags = 0;
703*5113495bSYour Name 	nlh->nlmsg_seq = 0;
704*5113495bSYour Name 	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
705*5113495bSYour Name 	ani_hdr = NLMSG_DATA(nlh);
706*5113495bSYour Name 	ani_hdr->type = ANI_MSG_PEER_STATUS_IND;
707*5113495bSYour Name 
708*5113495bSYour Name 	ani_hdr->length = sizeof(*peer_info);
709*5113495bSYour Name 	nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
710*5113495bSYour Name 
711*5113495bSYour Name 	peer_info = (struct peer_status_info *) ((char *)ani_hdr + sizeof(tAniMsgHdr));
712*5113495bSYour Name 	qdf_mem_zero(peer_info, sizeof(*peer_info));
713*5113495bSYour Name 	qdf_mem_copy(peer_info->peer_mac_addr, peer_mac->bytes,
714*5113495bSYour Name 		     sizeof(peer_mac->bytes));
715*5113495bSYour Name 	peer_info->peer_status = peer_status;
716*5113495bSYour Name 	peer_info->vdev_id = vdev_id;
717*5113495bSYour Name 	peer_info->peer_capability = peer_capability;
718*5113495bSYour Name 	/* Set 0th bit of reserved0 for STA mode */
719*5113495bSYour Name 	if (QDF_STA_MODE == dev_mode)
720*5113495bSYour Name 		peer_info->reserved0 |= 0x01;
721*5113495bSYour Name 
722*5113495bSYour Name 	if (chan_info) {
723*5113495bSYour Name 		peer_info->peer_chan_info.reserved0 = 0;
724*5113495bSYour Name 		peer_info->peer_chan_info.mhz = chan_info->mhz;
725*5113495bSYour Name 		peer_info->peer_chan_info.band_center_freq1 =
726*5113495bSYour Name 			chan_info->band_center_freq1;
727*5113495bSYour Name 		peer_info->peer_chan_info.band_center_freq2 =
728*5113495bSYour Name 			chan_info->band_center_freq2;
729*5113495bSYour Name 		peer_info->peer_chan_info.info = chan_info->info;
730*5113495bSYour Name 		peer_info->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
731*5113495bSYour Name 		peer_info->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
732*5113495bSYour Name 	}
733*5113495bSYour Name 	skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
734*5113495bSYour Name 
735*5113495bSYour Name 	hdd_info("sending peer " QDF_MAC_ADDR_FMT
736*5113495bSYour Name 		  " status(%d), peer_capability(%d), vdev_id(%d),"
737*5113495bSYour Name 		  " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d),"
738*5113495bSYour Name 		  " info (0x%x), frequency (%d),reg info 1 (0x%x),"
739*5113495bSYour Name 		  " reg info 2 (0x%x)",
740*5113495bSYour Name 		  QDF_MAC_ADDR_REF(peer_mac->bytes),
741*5113495bSYour Name 		  peer_status, peer_capability,
742*5113495bSYour Name 		  vdev_id, p_hdd_ctx->oem_pid,
743*5113495bSYour Name 		  peer_info->peer_chan_info.band_center_freq1,
744*5113495bSYour Name 		  peer_info->peer_chan_info.band_center_freq2,
745*5113495bSYour Name 		  peer_info->peer_chan_info.info,
746*5113495bSYour Name 		  peer_info->peer_chan_info.mhz,
747*5113495bSYour Name 		  peer_info->peer_chan_info.reg_info_1,
748*5113495bSYour Name 		  peer_info->peer_chan_info.reg_info_2);
749*5113495bSYour Name 
750*5113495bSYour Name 	(void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
751*5113495bSYour Name }
752*5113495bSYour Name 
753*5113495bSYour Name /**
754*5113495bSYour Name  * oem_app_reg_req_handler() - function to handle APP registration request
755*5113495bSYour Name  *                             from userspace
756*5113495bSYour Name  * @hdd_ctx: handle to HDD context
757*5113495bSYour Name  * @msg_hdr: pointer to ANI message header
758*5113495bSYour Name  * @pid: Process ID
759*5113495bSYour Name  *
760*5113495bSYour Name  * Return: 0 if success, error code otherwise
761*5113495bSYour Name  */
oem_app_reg_req_handler(struct hdd_context * hdd_ctx,tAniMsgHdr * msg_hdr,int pid)762*5113495bSYour Name static int oem_app_reg_req_handler(struct hdd_context *hdd_ctx,
763*5113495bSYour Name 				   tAniMsgHdr *msg_hdr, int pid)
764*5113495bSYour Name {
765*5113495bSYour Name 	char *sign_str = NULL;
766*5113495bSYour Name 
767*5113495bSYour Name 	/* Registration request is only allowed for Qualcomm Application */
768*5113495bSYour Name 	hdd_debug("Received App Req Req from App pid: %d len: %d",
769*5113495bSYour Name 			   pid, msg_hdr->length);
770*5113495bSYour Name 
771*5113495bSYour Name 	sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr));
772*5113495bSYour Name 	if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) &&
773*5113495bSYour Name 			(0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR,
774*5113495bSYour Name 				      OEM_APP_SIGNATURE_LEN))) {
775*5113495bSYour Name 		hdd_debug("Valid App Req Req from oem app pid: %d", pid);
776*5113495bSYour Name 
777*5113495bSYour Name 		hdd_ctx->oem_app_registered = true;
778*5113495bSYour Name 		hdd_ctx->oem_pid = pid;
779*5113495bSYour Name 		send_oem_reg_rsp_nlink_msg();
780*5113495bSYour Name 	} else {
781*5113495bSYour Name 		hdd_err("Invalid signature in App Reg Req from pid: %d", pid);
782*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_SIGNATURE);
783*5113495bSYour Name 		return -EPERM;
784*5113495bSYour Name 	}
785*5113495bSYour Name 
786*5113495bSYour Name 	return 0;
787*5113495bSYour Name }
788*5113495bSYour Name 
789*5113495bSYour Name /**
790*5113495bSYour Name  * oem_data_req_handler() - function to handle data_req from userspace
791*5113495bSYour Name  * @hdd_ctx: handle to HDD context
792*5113495bSYour Name  * @msg_hdr: pointer to ANI message header
793*5113495bSYour Name  * @pid: Process ID
794*5113495bSYour Name  *
795*5113495bSYour Name  * Return: 0 if success, error code otherwise
796*5113495bSYour Name  */
oem_data_req_handler(struct hdd_context * hdd_ctx,tAniMsgHdr * msg_hdr,int pid)797*5113495bSYour Name static int oem_data_req_handler(struct hdd_context *hdd_ctx,
798*5113495bSYour Name 				tAniMsgHdr *msg_hdr, int pid)
799*5113495bSYour Name {
800*5113495bSYour Name 	hdd_debug("Received Oem Data Request length: %d from pid: %d",
801*5113495bSYour Name 			msg_hdr->length, pid);
802*5113495bSYour Name 
803*5113495bSYour Name 	if ((!hdd_ctx->oem_app_registered) ||
804*5113495bSYour Name 			(pid != hdd_ctx->oem_pid)) {
805*5113495bSYour Name 		/* either oem app is not registered yet or pid is different */
806*5113495bSYour Name 		hdd_err("OEM DataReq: app not registered(%d) or incorrect pid(%d)",
807*5113495bSYour Name 				hdd_ctx->oem_app_registered, pid);
808*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED);
809*5113495bSYour Name 		return -EPERM;
810*5113495bSYour Name 	}
811*5113495bSYour Name 
812*5113495bSYour Name 	if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) {
813*5113495bSYour Name 		hdd_err("Invalid length (%d) in Oem Data Request",
814*5113495bSYour Name 				msg_hdr->length);
815*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH);
816*5113495bSYour Name 		return -EPERM;
817*5113495bSYour Name 	}
818*5113495bSYour Name 
819*5113495bSYour Name 	oem_process_data_req_msg(msg_hdr->length,
820*5113495bSYour Name 			(char *) ((char *)msg_hdr +
821*5113495bSYour Name 				sizeof(tAniMsgHdr)));
822*5113495bSYour Name 
823*5113495bSYour Name 	return 0;
824*5113495bSYour Name }
825*5113495bSYour Name 
826*5113495bSYour Name /**
827*5113495bSYour Name  * oem_chan_info_req_handler() - function to handle chan_info_req from userspace
828*5113495bSYour Name  * @hdd_ctx: handle to HDD context
829*5113495bSYour Name  * @msg_hdr: pointer to ANI message header
830*5113495bSYour Name  * @pid: Process ID
831*5113495bSYour Name  *
832*5113495bSYour Name  * Return: 0 if success, error code otherwise
833*5113495bSYour Name  */
oem_chan_info_req_handler(struct hdd_context * hdd_ctx,tAniMsgHdr * msg_hdr,int pid)834*5113495bSYour Name static int oem_chan_info_req_handler(struct hdd_context *hdd_ctx,
835*5113495bSYour Name 					tAniMsgHdr *msg_hdr, int pid)
836*5113495bSYour Name {
837*5113495bSYour Name 	hdd_debug("Received channel info request, num channel(%d) from pid: %d",
838*5113495bSYour Name 			msg_hdr->length, pid);
839*5113495bSYour Name 
840*5113495bSYour Name 	if ((!hdd_ctx->oem_app_registered) ||
841*5113495bSYour Name 			(pid != hdd_ctx->oem_pid)) {
842*5113495bSYour Name 		/* either oem app is not registered yet or pid is different */
843*5113495bSYour Name 		hdd_err("Chan InfoReq: app not registered(%d) or incorrect pid(%d)",
844*5113495bSYour Name 				hdd_ctx->oem_app_registered, pid);
845*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED);
846*5113495bSYour Name 		return -EPERM;
847*5113495bSYour Name 	}
848*5113495bSYour Name 
849*5113495bSYour Name 	/* message length contains list of channel ids */
850*5113495bSYour Name 	if ((!msg_hdr->length) ||
851*5113495bSYour Name 			(CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) {
852*5113495bSYour Name 		hdd_err("Invalid length (%d) in channel info request",
853*5113495bSYour Name 				msg_hdr->length);
854*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH);
855*5113495bSYour Name 		return -EPERM;
856*5113495bSYour Name 	}
857*5113495bSYour Name 	oem_process_channel_info_req_msg(msg_hdr->length,
858*5113495bSYour Name 			(char *)((char *)msg_hdr + sizeof(tAniMsgHdr)));
859*5113495bSYour Name 
860*5113495bSYour Name 	return 0;
861*5113495bSYour Name }
862*5113495bSYour Name 
863*5113495bSYour Name /**
864*5113495bSYour Name  * oem_set_cap_req_handler() - function to handle set_cap_req from userspace
865*5113495bSYour Name  * @hdd_ctx: handle to HDD context
866*5113495bSYour Name  * @msg_hdr: pointer to ANI message header
867*5113495bSYour Name  * @pid: Process ID
868*5113495bSYour Name  *
869*5113495bSYour Name  * Return: 0 if success, error code otherwise
870*5113495bSYour Name  */
oem_set_cap_req_handler(struct hdd_context * hdd_ctx,tAniMsgHdr * msg_hdr,int pid)871*5113495bSYour Name static int oem_set_cap_req_handler(struct hdd_context *hdd_ctx,
872*5113495bSYour Name 					tAniMsgHdr *msg_hdr, int pid)
873*5113495bSYour Name {
874*5113495bSYour Name 	hdd_info("Received set oem cap req of length:%d from pid: %d",
875*5113495bSYour Name 			msg_hdr->length, pid);
876*5113495bSYour Name 
877*5113495bSYour Name 	if ((!hdd_ctx->oem_app_registered) ||
878*5113495bSYour Name 			(pid != hdd_ctx->oem_pid)) {
879*5113495bSYour Name 		/* oem app is not registered yet or pid is different */
880*5113495bSYour Name 		hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)",
881*5113495bSYour Name 				hdd_ctx->oem_app_registered, pid);
882*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED);
883*5113495bSYour Name 		return -EPERM;
884*5113495bSYour Name 	}
885*5113495bSYour Name 
886*5113495bSYour Name 	if ((!msg_hdr->length) ||
887*5113495bSYour Name 			(sizeof(struct sme_oem_capability) < msg_hdr->length)) {
888*5113495bSYour Name 		hdd_err("Invalid length (%d) in set_oem_capability",
889*5113495bSYour Name 				msg_hdr->length);
890*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH);
891*5113495bSYour Name 		return -EPERM;
892*5113495bSYour Name 	}
893*5113495bSYour Name 
894*5113495bSYour Name 	oem_process_set_cap_req_msg(msg_hdr->length, (char *)
895*5113495bSYour Name 			((char *)msg_hdr + sizeof(tAniMsgHdr)),
896*5113495bSYour Name 			pid);
897*5113495bSYour Name 	return 0;
898*5113495bSYour Name }
899*5113495bSYour Name 
900*5113495bSYour Name /**
901*5113495bSYour Name  * oem_get_cap_req_handler() - function to handle get_cap_req from userspace
902*5113495bSYour Name  * @hdd_ctx: handle to HDD context
903*5113495bSYour Name  * @msg_hdr: pointer to ANI message header
904*5113495bSYour Name  * @pid: Process ID
905*5113495bSYour Name  *
906*5113495bSYour Name  * Return: 0 if success, error code otherwise
907*5113495bSYour Name  */
oem_get_cap_req_handler(struct hdd_context * hdd_ctx,tAniMsgHdr * msg_hdr,int pid)908*5113495bSYour Name static int oem_get_cap_req_handler(struct hdd_context *hdd_ctx,
909*5113495bSYour Name 					tAniMsgHdr *msg_hdr, int pid)
910*5113495bSYour Name {
911*5113495bSYour Name 	hdd_info("Rcvd get oem capability req - length:%d from pid: %d",
912*5113495bSYour Name 			msg_hdr->length, pid);
913*5113495bSYour Name 
914*5113495bSYour Name 	if ((!hdd_ctx->oem_app_registered) ||
915*5113495bSYour Name 			(pid != hdd_ctx->oem_pid)) {
916*5113495bSYour Name 		/* oem app is not registered yet or pid is different */
917*5113495bSYour Name 		hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)",
918*5113495bSYour Name 				hdd_ctx->oem_app_registered, pid);
919*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED);
920*5113495bSYour Name 		return -EPERM;
921*5113495bSYour Name 	}
922*5113495bSYour Name 
923*5113495bSYour Name 	oem_process_get_cap_req_msg();
924*5113495bSYour Name 	return 0;
925*5113495bSYour Name }
926*5113495bSYour Name 
927*5113495bSYour Name /**
928*5113495bSYour Name  * oem_request_dispatcher() - OEM command dispatcher API
929*5113495bSYour Name  * @msg_hdr: ANI Message Header
930*5113495bSYour Name  * @pid: process id
931*5113495bSYour Name  *
932*5113495bSYour Name  * This API is used to dispatch the command from OEM depending
933*5113495bSYour Name  * on the type of the message received.
934*5113495bSYour Name  *
935*5113495bSYour Name  * Return: None
936*5113495bSYour Name  */
oem_request_dispatcher(tAniMsgHdr * msg_hdr,int pid)937*5113495bSYour Name static void oem_request_dispatcher(tAniMsgHdr *msg_hdr, int pid)
938*5113495bSYour Name {
939*5113495bSYour Name 	switch (msg_hdr->type) {
940*5113495bSYour Name 	case ANI_MSG_APP_REG_REQ:
941*5113495bSYour Name 		oem_app_reg_req_handler(p_hdd_ctx, msg_hdr, pid);
942*5113495bSYour Name 		break;
943*5113495bSYour Name 
944*5113495bSYour Name 	case ANI_MSG_OEM_DATA_REQ:
945*5113495bSYour Name 		oem_data_req_handler(p_hdd_ctx, msg_hdr, pid);
946*5113495bSYour Name 		break;
947*5113495bSYour Name 
948*5113495bSYour Name 	case ANI_MSG_CHANNEL_INFO_REQ:
949*5113495bSYour Name 		oem_chan_info_req_handler(p_hdd_ctx, msg_hdr, pid);
950*5113495bSYour Name 		break;
951*5113495bSYour Name 
952*5113495bSYour Name 	case ANI_MSG_SET_OEM_CAP_REQ:
953*5113495bSYour Name 		oem_set_cap_req_handler(p_hdd_ctx, msg_hdr, pid);
954*5113495bSYour Name 		break;
955*5113495bSYour Name 
956*5113495bSYour Name 	case ANI_MSG_GET_OEM_CAP_REQ:
957*5113495bSYour Name 		oem_get_cap_req_handler(p_hdd_ctx, msg_hdr, pid);
958*5113495bSYour Name 		break;
959*5113495bSYour Name 
960*5113495bSYour Name 	default:
961*5113495bSYour Name 		hdd_err("Received Invalid message type (%d), length (%d)",
962*5113495bSYour Name 				msg_hdr->type, msg_hdr->length);
963*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_TYPE);
964*5113495bSYour Name 	}
965*5113495bSYour Name }
966*5113495bSYour Name 
967*5113495bSYour Name #ifdef CNSS_GENL
968*5113495bSYour Name /**
969*5113495bSYour Name  * oem_cmd_handler() - API to handle OEM commands
970*5113495bSYour Name  * @data: Pointer to data
971*5113495bSYour Name  * @data_len: length of the received data
972*5113495bSYour Name  * @ctx: Pointer to the context
973*5113495bSYour Name  * @pid: Process id
974*5113495bSYour Name  *
975*5113495bSYour Name  * This API handles the command from OEM application from user space and
976*5113495bSYour Name  * send back event to user space if necessary.
977*5113495bSYour Name  *
978*5113495bSYour Name  * Return: None
979*5113495bSYour Name  */
oem_cmd_handler(const void * data,int data_len,void * ctx,int pid)980*5113495bSYour Name static void oem_cmd_handler(const void *data, int data_len, void *ctx, int pid)
981*5113495bSYour Name {
982*5113495bSYour Name 	tAniMsgHdr *msg_hdr;
983*5113495bSYour Name 	int msg_len;
984*5113495bSYour Name 	int ret;
985*5113495bSYour Name 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
986*5113495bSYour Name 
987*5113495bSYour Name 	ret = wlan_hdd_validate_context(p_hdd_ctx);
988*5113495bSYour Name 	if (ret)
989*5113495bSYour Name 		return;
990*5113495bSYour Name 
991*5113495bSYour Name 	/*
992*5113495bSYour Name 	 * audit note: it is ok to pass a NULL policy here since only
993*5113495bSYour Name 	 * one attribute is parsed and it is explicitly validated
994*5113495bSYour Name 	 */
995*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX,
996*5113495bSYour Name 				    data, data_len, NULL)) {
997*5113495bSYour Name 		hdd_err("Invalid ATTR");
998*5113495bSYour Name 		return;
999*5113495bSYour Name 	}
1000*5113495bSYour Name 
1001*5113495bSYour Name 	if (!tb[CLD80211_ATTR_DATA]) {
1002*5113495bSYour Name 		hdd_err("attr ATTR_DATA failed");
1003*5113495bSYour Name 		return;
1004*5113495bSYour Name 	}
1005*5113495bSYour Name 
1006*5113495bSYour Name 	msg_len = nla_len(tb[CLD80211_ATTR_DATA]);
1007*5113495bSYour Name 	if (msg_len < sizeof(*msg_hdr)) {
1008*5113495bSYour Name 		hdd_err("runt ATTR_DATA size %d", msg_len);
1009*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_NULL_MESSAGE_HEADER);
1010*5113495bSYour Name 		return;
1011*5113495bSYour Name 	}
1012*5113495bSYour Name 
1013*5113495bSYour Name 	msg_hdr = nla_data(tb[CLD80211_ATTR_DATA]);
1014*5113495bSYour Name 	if (msg_len < (sizeof(*msg_hdr) + msg_hdr->length)) {
1015*5113495bSYour Name 		hdd_err("Invalid nl msg len %d, msg hdr len %d",
1016*5113495bSYour Name 			msg_len, msg_hdr->length);
1017*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH);
1018*5113495bSYour Name 		return;
1019*5113495bSYour Name 	}
1020*5113495bSYour Name 
1021*5113495bSYour Name 	oem_request_dispatcher(msg_hdr, pid);
1022*5113495bSYour Name }
1023*5113495bSYour Name 
oem_activate_service(struct hdd_context * hdd_ctx)1024*5113495bSYour Name int oem_activate_service(struct hdd_context *hdd_ctx)
1025*5113495bSYour Name {
1026*5113495bSYour Name 	p_hdd_ctx = hdd_ctx;
1027*5113495bSYour Name 	register_cld_cmd_cb(WLAN_NL_MSG_OEM, oem_cmd_handler, NULL);
1028*5113495bSYour Name 	return 0;
1029*5113495bSYour Name }
1030*5113495bSYour Name 
oem_deactivate_service(void)1031*5113495bSYour Name int oem_deactivate_service(void)
1032*5113495bSYour Name {
1033*5113495bSYour Name 	deregister_cld_cmd_cb(WLAN_NL_MSG_OEM);
1034*5113495bSYour Name 	return 0;
1035*5113495bSYour Name }
1036*5113495bSYour Name #else
1037*5113495bSYour Name 
1038*5113495bSYour Name /*
1039*5113495bSYour Name  * Callback function invoked by Netlink service for all netlink
1040*5113495bSYour Name  * messages (from user space) addressed to WLAN_NL_MSG_OEM
1041*5113495bSYour Name  */
1042*5113495bSYour Name 
1043*5113495bSYour Name /**
1044*5113495bSYour Name  * oem_msg_callback() - callback invoked by netlink service
1045*5113495bSYour Name  * @skb:    skb with netlink message
1046*5113495bSYour Name  *
1047*5113495bSYour Name  * This function gets invoked by netlink service when a message
1048*5113495bSYour Name  * is received from user space addressed to WLAN_NL_MSG_OEM
1049*5113495bSYour Name  *
1050*5113495bSYour Name  * Return: zero on success
1051*5113495bSYour Name  *         On error, error number will be returned.
1052*5113495bSYour Name  */
oem_msg_callback(struct sk_buff * skb)1053*5113495bSYour Name static int oem_msg_callback(struct sk_buff *skb)
1054*5113495bSYour Name {
1055*5113495bSYour Name 	struct nlmsghdr *nlh;
1056*5113495bSYour Name 	tAniMsgHdr *msg_hdr;
1057*5113495bSYour Name 	int ret;
1058*5113495bSYour Name 
1059*5113495bSYour Name 	nlh = (struct nlmsghdr *)skb->data;
1060*5113495bSYour Name 	if (!nlh) {
1061*5113495bSYour Name 		hdd_err("Netlink header null");
1062*5113495bSYour Name 		return -EPERM;
1063*5113495bSYour Name 	}
1064*5113495bSYour Name 
1065*5113495bSYour Name 	ret = wlan_hdd_validate_context(p_hdd_ctx);
1066*5113495bSYour Name 	if (ret)
1067*5113495bSYour Name 		return ret;
1068*5113495bSYour Name 
1069*5113495bSYour Name 	msg_hdr = NLMSG_DATA(nlh);
1070*5113495bSYour Name 
1071*5113495bSYour Name 	if (!msg_hdr) {
1072*5113495bSYour Name 		hdd_err("Message header null");
1073*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
1074*5113495bSYour Name 					   OEM_ERR_NULL_MESSAGE_HEADER);
1075*5113495bSYour Name 		return -EPERM;
1076*5113495bSYour Name 	}
1077*5113495bSYour Name 
1078*5113495bSYour Name 	if (nlh->nlmsg_len <
1079*5113495bSYour Name 	    NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) {
1080*5113495bSYour Name 		hdd_err("Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)",
1081*5113495bSYour Name 			nlh->nlmsg_len, msg_hdr->length);
1082*5113495bSYour Name 		send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
1083*5113495bSYour Name 					   OEM_ERR_INVALID_MESSAGE_LENGTH);
1084*5113495bSYour Name 		return -EPERM;
1085*5113495bSYour Name 	}
1086*5113495bSYour Name 
1087*5113495bSYour Name 	oem_request_dispatcher(msg_hdr, nlh->nlmsg_pid);
1088*5113495bSYour Name 	return 0;
1089*5113495bSYour Name }
1090*5113495bSYour Name 
__oem_msg_callback(struct sk_buff * skb)1091*5113495bSYour Name static int __oem_msg_callback(struct sk_buff *skb)
1092*5113495bSYour Name {
1093*5113495bSYour Name 	struct hdd_context *hdd_ctx = p_hdd_ctx;
1094*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
1095*5113495bSYour Name 	int errno;
1096*5113495bSYour Name 
1097*5113495bSYour Name 	errno = wlan_hdd_validate_context(hdd_ctx);
1098*5113495bSYour Name 	if (errno)
1099*5113495bSYour Name 		return errno;
1100*5113495bSYour Name 
1101*5113495bSYour Name 	errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
1102*5113495bSYour Name 	if (errno)
1103*5113495bSYour Name 		return errno;
1104*5113495bSYour Name 
1105*5113495bSYour Name 	errno = oem_msg_callback(skb);
1106*5113495bSYour Name 
1107*5113495bSYour Name 	osif_psoc_sync_op_stop(psoc_sync);
1108*5113495bSYour Name 
1109*5113495bSYour Name 	return errno;
1110*5113495bSYour Name }
1111*5113495bSYour Name 
oem_activate_service(struct hdd_context * hdd_ctx)1112*5113495bSYour Name int oem_activate_service(struct hdd_context *hdd_ctx)
1113*5113495bSYour Name {
1114*5113495bSYour Name 	p_hdd_ctx = hdd_ctx;
1115*5113495bSYour Name 
1116*5113495bSYour Name 	/* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
1117*5113495bSYour Name 	return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback);
1118*5113495bSYour Name }
1119*5113495bSYour Name 
oem_deactivate_service(void)1120*5113495bSYour Name int oem_deactivate_service(void)
1121*5113495bSYour Name {
1122*5113495bSYour Name 	/* Deregister the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
1123*5113495bSYour Name 	return nl_srv_unregister(WLAN_NL_MSG_OEM, __oem_msg_callback);
1124*5113495bSYour Name }
1125*5113495bSYour Name 
1126*5113495bSYour Name #endif
1127*5113495bSYour Name #endif
1128*5113495bSYour Name 
1129*5113495bSYour Name #ifdef FEATURE_OEM_DATA
1130*5113495bSYour Name const struct nla_policy
1131*5113495bSYour Name oem_data_attr_policy[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1] = {
1132*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA] = {
1133*5113495bSYour Name 						    .type = NLA_BINARY,
1134*5113495bSYour Name 						    .len = OEM_DATA_MAX_SIZE
1135*5113495bSYour Name 	},
1136*5113495bSYour Name 
1137*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO] = {.type = NLA_U8},
1138*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED] = {.type = NLA_FLAG},
1139*5113495bSYour Name };
1140*5113495bSYour Name 
1141*5113495bSYour Name /**
1142*5113495bSYour Name  * hdd_copy_file_name_and_oem_data() - Copy file name and oem data
1143*5113495bSYour Name  * @hdd_ctx: pointer to hdd context
1144*5113495bSYour Name  * @oem_event_data: oem event data param buffe
1145*5113495bSYour Name  *
1146*5113495bSYour Name  * Return: none
1147*5113495bSYour Name  */
hdd_copy_file_name_and_oem_data(struct hdd_context * hdd_ctx,const struct oem_data * oem_event_data)1148*5113495bSYour Name static void hdd_copy_file_name_and_oem_data(
1149*5113495bSYour Name 				struct hdd_context *hdd_ctx,
1150*5113495bSYour Name 				const struct oem_data *oem_event_data)
1151*5113495bSYour Name {
1152*5113495bSYour Name 	if (!oem_event_data->data_len || !oem_event_data->file_name_len) {
1153*5113495bSYour Name 		hdd_err("Invalid file name or data length");
1154*5113495bSYour Name 		return;
1155*5113495bSYour Name 	}
1156*5113495bSYour Name 
1157*5113495bSYour Name 	if (oem_event_data->data_len > HDD_MAX_OEM_DATA_LEN ||
1158*5113495bSYour Name 	    oem_event_data->file_name_len > HDD_MAX_FILE_NAME_LEN) {
1159*5113495bSYour Name 		hdd_err("Invalid oem data len %zu or file name len %d",
1160*5113495bSYour Name 			oem_event_data->data_len,
1161*5113495bSYour Name 			oem_event_data->file_name_len);
1162*5113495bSYour Name 		return;
1163*5113495bSYour Name 	}
1164*5113495bSYour Name 	qdf_mem_zero(hdd_ctx->oem_data, HDD_MAX_OEM_DATA_LEN);
1165*5113495bSYour Name 	qdf_mem_zero(hdd_ctx->file_name, HDD_MAX_FILE_NAME_LEN);
1166*5113495bSYour Name 
1167*5113495bSYour Name 	qdf_mem_copy(hdd_ctx->oem_data, oem_event_data->data,
1168*5113495bSYour Name 		     oem_event_data->data_len);
1169*5113495bSYour Name 	hdd_ctx->oem_data_len = oem_event_data->data_len;
1170*5113495bSYour Name 
1171*5113495bSYour Name 	qdf_mem_copy(hdd_ctx->file_name, oem_event_data->file_name,
1172*5113495bSYour Name 		     oem_event_data->file_name_len);
1173*5113495bSYour Name }
1174*5113495bSYour Name 
hdd_oem_event_async_cb(const struct oem_data * oem_event_data)1175*5113495bSYour Name void hdd_oem_event_async_cb(const struct oem_data *oem_event_data)
1176*5113495bSYour Name {
1177*5113495bSYour Name 	struct sk_buff *vendor_event;
1178*5113495bSYour Name 	uint32_t len;
1179*5113495bSYour Name 	int ret;
1180*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1181*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1182*5113495bSYour Name 	struct wireless_dev *wdev = NULL;
1183*5113495bSYour Name 
1184*5113495bSYour Name 	hdd_enter();
1185*5113495bSYour Name 
1186*5113495bSYour Name 	if (!hdd_ctx)
1187*5113495bSYour Name 		return;
1188*5113495bSYour Name 
1189*5113495bSYour Name 	if (oem_event_data->file_name) {
1190*5113495bSYour Name 		hdd_copy_file_name_and_oem_data(hdd_ctx, oem_event_data);
1191*5113495bSYour Name 		return;
1192*5113495bSYour Name 	}
1193*5113495bSYour Name 
1194*5113495bSYour Name 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, oem_event_data->vdev_id);
1195*5113495bSYour Name 	if (link_info)
1196*5113495bSYour Name 		wdev = &link_info->adapter->wdev;
1197*5113495bSYour Name 
1198*5113495bSYour Name 	len = nla_total_size(oem_event_data->data_len) + NLMSG_HDRLEN;
1199*5113495bSYour Name 	vendor_event = wlan_cfg80211_vendor_event_alloc(
1200*5113495bSYour Name 				hdd_ctx->wiphy, wdev, len,
1201*5113495bSYour Name 				QCA_NL80211_VENDOR_SUBCMD_OEM_DATA_INDEX,
1202*5113495bSYour Name 				GFP_KERNEL);
1203*5113495bSYour Name 
1204*5113495bSYour Name 	if (!vendor_event) {
1205*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
1206*5113495bSYour Name 		return;
1207*5113495bSYour Name 	}
1208*5113495bSYour Name 
1209*5113495bSYour Name 	ret = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA,
1210*5113495bSYour Name 		      oem_event_data->data_len, oem_event_data->data);
1211*5113495bSYour Name 	if (ret) {
1212*5113495bSYour Name 		hdd_err("OEM event put fails status %d", ret);
1213*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(vendor_event);
1214*5113495bSYour Name 		return;
1215*5113495bSYour Name 	}
1216*5113495bSYour Name 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
1217*5113495bSYour Name 	hdd_exit();
1218*5113495bSYour Name }
1219*5113495bSYour Name 
hdd_oem_event_handler_cb(const struct oem_data * oem_event_data,uint8_t vdev_id)1220*5113495bSYour Name void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data,
1221*5113495bSYour Name 			      uint8_t vdev_id)
1222*5113495bSYour Name {
1223*5113495bSYour Name 	struct sk_buff *vendor_event;
1224*5113495bSYour Name 	struct osif_request *request;
1225*5113495bSYour Name 	uint32_t len;
1226*5113495bSYour Name 	int ret;
1227*5113495bSYour Name 	struct oem_data *oem_data;
1228*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
1229*5113495bSYour Name 	struct wlan_hdd_link_info *link_info;
1230*5113495bSYour Name 	struct hdd_adapter *hdd_adapter;
1231*5113495bSYour Name 	struct wireless_dev *wdev = NULL;
1232*5113495bSYour Name 
1233*5113495bSYour Name 	hdd_enter();
1234*5113495bSYour Name 
1235*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
1236*5113495bSYour Name 	if (ret)
1237*5113495bSYour Name 		return;
1238*5113495bSYour Name 
1239*5113495bSYour Name 	if (!oem_event_data || !(oem_event_data->data)) {
1240*5113495bSYour Name 		hdd_err("Invalid oem event data");
1241*5113495bSYour Name 		return;
1242*5113495bSYour Name 	}
1243*5113495bSYour Name 
1244*5113495bSYour Name 	link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
1245*5113495bSYour Name 	if (!link_info || hdd_validate_adapter(link_info->adapter))
1246*5113495bSYour Name 		return;
1247*5113495bSYour Name 
1248*5113495bSYour Name 	hdd_adapter = link_info->adapter;
1249*5113495bSYour Name 	if (hdd_adapter->response_expected) {
1250*5113495bSYour Name 		request = osif_request_get(hdd_adapter->cookie);
1251*5113495bSYour Name 		if (!request) {
1252*5113495bSYour Name 			hdd_err("Invalid request");
1253*5113495bSYour Name 			return;
1254*5113495bSYour Name 		}
1255*5113495bSYour Name 
1256*5113495bSYour Name 		oem_data = osif_request_priv(request);
1257*5113495bSYour Name 		oem_data->data_len = oem_event_data->data_len;
1258*5113495bSYour Name 		oem_data->data = qdf_mem_malloc(oem_data->data_len);
1259*5113495bSYour Name 		if (!oem_data->data) {
1260*5113495bSYour Name 			osif_request_put(request);
1261*5113495bSYour Name 			return;
1262*5113495bSYour Name 		}
1263*5113495bSYour Name 
1264*5113495bSYour Name 		qdf_mem_copy(oem_data->data, oem_event_data->data,
1265*5113495bSYour Name 			     oem_data->data_len);
1266*5113495bSYour Name 		oem_data->vdev_id = link_info->vdev_id;
1267*5113495bSYour Name 		osif_request_complete(request);
1268*5113495bSYour Name 		osif_request_put(request);
1269*5113495bSYour Name 	} else {
1270*5113495bSYour Name 		wdev = &(hdd_adapter->wdev);
1271*5113495bSYour Name 
1272*5113495bSYour Name 		len = nla_total_size(oem_event_data->data_len) + NLMSG_HDRLEN;
1273*5113495bSYour Name 		vendor_event =
1274*5113495bSYour Name 			wlan_cfg80211_vendor_event_alloc(
1275*5113495bSYour Name 				hdd_ctx->wiphy, wdev, len,
1276*5113495bSYour Name 				QCA_NL80211_VENDOR_SUBCMD_OEM_DATA_INDEX,
1277*5113495bSYour Name 				GFP_KERNEL);
1278*5113495bSYour Name 
1279*5113495bSYour Name 		if (!vendor_event) {
1280*5113495bSYour Name 			hdd_err("wlan_cfg80211_vendor_event_alloc failed");
1281*5113495bSYour Name 			return;
1282*5113495bSYour Name 		}
1283*5113495bSYour Name 
1284*5113495bSYour Name 		ret = nla_put(vendor_event,
1285*5113495bSYour Name 			      QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA,
1286*5113495bSYour Name 			      oem_event_data->data_len, oem_event_data->data);
1287*5113495bSYour Name 		if (ret) {
1288*5113495bSYour Name 			hdd_err("OEM event put fails status %d", ret);
1289*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(vendor_event);
1290*5113495bSYour Name 			return;
1291*5113495bSYour Name 		}
1292*5113495bSYour Name 		wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
1293*5113495bSYour Name 	}
1294*5113495bSYour Name 	sme_oem_event_deinit(hdd_ctx->mac_handle);
1295*5113495bSYour Name 
1296*5113495bSYour Name 	hdd_exit();
1297*5113495bSYour Name }
1298*5113495bSYour Name 
1299*5113495bSYour Name /**
1300*5113495bSYour Name  *wlan_hdd_free_oem_data: delete data of priv data
1301*5113495bSYour Name  *@priv: osif request private data
1302*5113495bSYour Name  *
1303*5113495bSYour Name  *Return: void
1304*5113495bSYour Name  */
wlan_hdd_free_oem_data(void * priv)1305*5113495bSYour Name static void wlan_hdd_free_oem_data(void *priv)
1306*5113495bSYour Name {
1307*5113495bSYour Name 	struct oem_data *local_priv = priv;
1308*5113495bSYour Name 
1309*5113495bSYour Name 	if (!local_priv)
1310*5113495bSYour Name 		return;
1311*5113495bSYour Name 
1312*5113495bSYour Name 	if (local_priv->data) {
1313*5113495bSYour Name 		qdf_mem_free(local_priv->data);
1314*5113495bSYour Name 		local_priv->data = NULL;
1315*5113495bSYour Name 	}
1316*5113495bSYour Name }
1317*5113495bSYour Name 
1318*5113495bSYour Name /**
1319*5113495bSYour Name  * __wlan_hdd_cfg80211_oem_data_handler() - the handler for oem data
1320*5113495bSYour Name  * @wiphy: wiphy structure pointer
1321*5113495bSYour Name  * @wdev: Wireless device structure pointer
1322*5113495bSYour Name  * @data: Pointer to the data received
1323*5113495bSYour Name  * @data_len: Length of @data
1324*5113495bSYour Name  *
1325*5113495bSYour Name  * Return: 0 on success; errno on failure
1326*5113495bSYour Name  */
1327*5113495bSYour Name static int
__wlan_hdd_cfg80211_oem_data_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1328*5113495bSYour Name __wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy,
1329*5113495bSYour Name 				     struct wireless_dev *wdev,
1330*5113495bSYour Name 				     const void *data, int data_len)
1331*5113495bSYour Name {
1332*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
1333*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1334*5113495bSYour Name 	uint8_t mac_id;
1335*5113495bSYour Name 	int ret;
1336*5113495bSYour Name 	struct sk_buff *skb = NULL;
1337*5113495bSYour Name 	struct oem_data oem_data = {0};
1338*5113495bSYour Name 	struct oem_data *get_oem_data = NULL;
1339*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
1340*5113495bSYour Name 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1341*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1];
1342*5113495bSYour Name 	struct osif_request *request = NULL;
1343*5113495bSYour Name 	struct oem_data *priv;
1344*5113495bSYour Name 	static const struct osif_request_params params = {
1345*5113495bSYour Name 		.priv_size = sizeof(*priv),
1346*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_GET_OEM_DATA,
1347*5113495bSYour Name 		.dealloc = wlan_hdd_free_oem_data,
1348*5113495bSYour Name 	};
1349*5113495bSYour Name 
1350*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
1351*5113495bSYour Name 		hdd_err("Command not allowed in FTM mode");
1352*5113495bSYour Name 		return -EPERM;
1353*5113495bSYour Name 	}
1354*5113495bSYour Name 
1355*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
1356*5113495bSYour Name 	if (ret)
1357*5113495bSYour Name 		return ret;
1358*5113495bSYour Name 
1359*5113495bSYour Name 	if (hdd_validate_adapter(adapter))
1360*5113495bSYour Name 		return -EINVAL;
1361*5113495bSYour Name 
1362*5113495bSYour Name 	if (adapter->oem_data_in_progress) {
1363*5113495bSYour Name 		hdd_err("oem request already in progress");
1364*5113495bSYour Name 		return -EBUSY;
1365*5113495bSYour Name 	}
1366*5113495bSYour Name 
1367*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb,
1368*5113495bSYour Name 				    QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX,
1369*5113495bSYour Name 				    data, data_len, oem_data_attr_policy)) {
1370*5113495bSYour Name 		hdd_err("Invalid attributes");
1371*5113495bSYour Name 		return -EINVAL;
1372*5113495bSYour Name 	}
1373*5113495bSYour Name 
1374*5113495bSYour Name 	if (!tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]) {
1375*5113495bSYour Name 		hdd_err("oem data is missing!");
1376*5113495bSYour Name 		return -EINVAL;
1377*5113495bSYour Name 	}
1378*5113495bSYour Name 
1379*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO])
1380*5113495bSYour Name 		oem_data.pdev_vdev_flag =
1381*5113495bSYour Name 			nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO]);
1382*5113495bSYour Name 
1383*5113495bSYour Name 	if (oem_data.pdev_vdev_flag) {
1384*5113495bSYour Name 		status = policy_mgr_get_mac_id_by_session_id(
1385*5113495bSYour Name 						    hdd_ctx->psoc,
1386*5113495bSYour Name 						    adapter->deflink->vdev_id,
1387*5113495bSYour Name 						    &mac_id);
1388*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1389*5113495bSYour Name 			hdd_err("get mac id failed");
1390*5113495bSYour Name 			return -EINVAL;
1391*5113495bSYour Name 		}
1392*5113495bSYour Name 		oem_data.pdev_id = mac_id;
1393*5113495bSYour Name 		oem_data.is_host_pdev_id = true;
1394*5113495bSYour Name 	}
1395*5113495bSYour Name 	oem_data.data_len =
1396*5113495bSYour Name 		nla_len(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]);
1397*5113495bSYour Name 	if (!oem_data.data_len) {
1398*5113495bSYour Name 		hdd_err("oem data len is 0!");
1399*5113495bSYour Name 		return -EINVAL;
1400*5113495bSYour Name 	}
1401*5113495bSYour Name 	oem_data.vdev_id = adapter->deflink->vdev_id;
1402*5113495bSYour Name 	oem_data.data = nla_data(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]);
1403*5113495bSYour Name 
1404*5113495bSYour Name 	if (tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED])
1405*5113495bSYour Name 		adapter->response_expected = nla_get_flag(
1406*5113495bSYour Name 			   tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED]);
1407*5113495bSYour Name 
1408*5113495bSYour Name 	if (adapter->response_expected) {
1409*5113495bSYour Name 		int skb_len = 0;
1410*5113495bSYour Name 
1411*5113495bSYour Name 		adapter->oem_data_in_progress = true;
1412*5113495bSYour Name 		qdf_runtime_pm_prevent_suspend(
1413*5113495bSYour Name 					&hdd_ctx->runtime_context.oem_data_cmd);
1414*5113495bSYour Name 		request = osif_request_alloc(&params);
1415*5113495bSYour Name 		if (!request) {
1416*5113495bSYour Name 			hdd_err("request allocation failure");
1417*5113495bSYour Name 			ret = -ENOMEM;
1418*5113495bSYour Name 			goto err;
1419*5113495bSYour Name 		}
1420*5113495bSYour Name 
1421*5113495bSYour Name 		adapter->cookie = osif_request_cookie(request);
1422*5113495bSYour Name 
1423*5113495bSYour Name 		status = sme_oem_data_cmd(hdd_ctx->mac_handle,
1424*5113495bSYour Name 					  hdd_oem_event_handler_cb,
1425*5113495bSYour Name 					  &oem_data, adapter->deflink->vdev_id);
1426*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
1427*5113495bSYour Name 			hdd_err("Failure while sending command to fw");
1428*5113495bSYour Name 			ret = -EAGAIN;
1429*5113495bSYour Name 			goto err;
1430*5113495bSYour Name 		}
1431*5113495bSYour Name 		ret = osif_request_wait_for_response(request);
1432*5113495bSYour Name 		if (ret) {
1433*5113495bSYour Name 			hdd_err("Timedout while retrieving oem get data");
1434*5113495bSYour Name 			goto err;
1435*5113495bSYour Name 		}
1436*5113495bSYour Name 
1437*5113495bSYour Name 		get_oem_data = osif_request_priv(request);
1438*5113495bSYour Name 		if (!get_oem_data || !(get_oem_data->data)) {
1439*5113495bSYour Name 			hdd_err("invalid get_oem_data");
1440*5113495bSYour Name 			ret = -EINVAL;
1441*5113495bSYour Name 			goto err;
1442*5113495bSYour Name 		}
1443*5113495bSYour Name 
1444*5113495bSYour Name 		skb_len = NLMSG_HDRLEN + nla_total_size(get_oem_data->data_len);
1445*5113495bSYour Name 		skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1446*5113495bSYour Name 							       skb_len);
1447*5113495bSYour Name 		if (!skb) {
1448*5113495bSYour Name 			hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
1449*5113495bSYour Name 			ret = -ENOMEM;
1450*5113495bSYour Name 			goto err;
1451*5113495bSYour Name 		}
1452*5113495bSYour Name 
1453*5113495bSYour Name 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA,
1454*5113495bSYour Name 			    get_oem_data->data_len, get_oem_data->data)) {
1455*5113495bSYour Name 			hdd_err("nla put failure");
1456*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(skb);
1457*5113495bSYour Name 			ret =  -EINVAL;
1458*5113495bSYour Name 			goto err;
1459*5113495bSYour Name 		}
1460*5113495bSYour Name 		wlan_cfg80211_vendor_cmd_reply(skb);
1461*5113495bSYour Name 
1462*5113495bSYour Name 	} else {
1463*5113495bSYour Name 		status = sme_oem_data_cmd(hdd_ctx->mac_handle,
1464*5113495bSYour Name 					  hdd_oem_event_handler_cb,
1465*5113495bSYour Name 					  &oem_data, adapter->deflink->vdev_id);
1466*5113495bSYour Name 		return qdf_status_to_os_return(status);
1467*5113495bSYour Name 	}
1468*5113495bSYour Name 
1469*5113495bSYour Name err:
1470*5113495bSYour Name 	if (request)
1471*5113495bSYour Name 		osif_request_put(request);
1472*5113495bSYour Name 	adapter->oem_data_in_progress = false;
1473*5113495bSYour Name 	adapter->response_expected = false;
1474*5113495bSYour Name 	qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.oem_data_cmd);
1475*5113495bSYour Name 
1476*5113495bSYour Name 	return ret;
1477*5113495bSYour Name 
1478*5113495bSYour Name }
1479*5113495bSYour Name 
wlan_hdd_cfg80211_oem_data_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)1480*5113495bSYour Name int wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy,
1481*5113495bSYour Name 				       struct wireless_dev *wdev,
1482*5113495bSYour Name 				       const void *data, int data_len)
1483*5113495bSYour Name {
1484*5113495bSYour Name 	struct osif_vdev_sync *vdev_sync;
1485*5113495bSYour Name 	int ret;
1486*5113495bSYour Name 
1487*5113495bSYour Name 	ret = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
1488*5113495bSYour Name 	if (ret)
1489*5113495bSYour Name 		return ret;
1490*5113495bSYour Name 
1491*5113495bSYour Name 	ret = __wlan_hdd_cfg80211_oem_data_handler(wiphy, wdev,
1492*5113495bSYour Name 						   data, data_len);
1493*5113495bSYour Name 	osif_vdev_sync_op_stop(vdev_sync);
1494*5113495bSYour Name 
1495*5113495bSYour Name 	return ret;
1496*5113495bSYour Name }
1497*5113495bSYour Name #endif
1498*5113495bSYour Name #endif
1499