blob: 01bd3c8c7af4f6fbffc4b8f9a00b6036df92091c [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05302 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28#ifdef FEATURE_OEM_DATA_SUPPORT
29
30/**
31 * DOC: wlan_hdd_oemdata.c
32 *
33 * Support for generic OEM Data Request handling
34 *
35 */
36
37#include <linux/version.h>
38#include <linux/module.h>
39#include <linux/kernel.h>
40#include <linux/init.h>
41#include <linux/wireless.h>
42#include <wlan_hdd_includes.h>
43#include <net/arp.h>
44#include "qwlan_version.h"
45#include "cds_utils.h"
46#include "wma.h"
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080047#include "sme_api.h"
Naveen Rawatdd761802017-03-20 09:56:28 -070048#include "wlan_nlink_srv.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080049
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +053050#ifdef CNSS_GENL
51#include <net/cnss_nl.h>
52#endif
53
Jeff Johnson82797b62017-08-11 15:31:27 -070054static struct hdd_context *p_hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080055
56/**
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080057 * populate_oem_data_cap() - populate oem capabilities
58 * @adapter: device adapter
59 * @data_cap: pointer to populate the capabilities
60 *
61 * Return: error code
62 */
Jeff Johnsonda47af82017-08-29 14:26:44 -070063static int populate_oem_data_cap(struct hdd_adapter *adapter,
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -070064 struct oem_data_cap *data_cap)
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080065{
Krishna Kumaar Natarajanc4f8a932016-04-16 13:51:42 +053066 QDF_STATUS status;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080067 struct hdd_config *config;
68 uint32_t num_chan;
69 uint8_t *chan_list;
Jeff Johnson1e3e3ee2017-08-28 11:47:40 -070070 struct hdd_context *hdd_ctx = adapter->pHddCtx;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080071
72 config = hdd_ctx->config;
73 if (!config) {
74 hdd_err("HDD configuration is null");
75 return -EINVAL;
76 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +053077 chan_list = qdf_mem_malloc(sizeof(uint8_t) * OEM_CAP_MAX_NUM_CHANNELS);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080078 if (NULL == chan_list) {
79 hdd_err("Memory allocation failed");
80 return -ENOMEM;
81 }
82
83 strlcpy(data_cap->oem_target_signature, OEM_TARGET_SIGNATURE,
84 OEM_TARGET_SIGNATURE_LEN);
85 data_cap->oem_target_type = hdd_ctx->target_type;
86 data_cap->oem_fw_version = hdd_ctx->target_fw_version;
87 data_cap->driver_version.major = QWLAN_VERSION_MAJOR;
88 data_cap->driver_version.minor = QWLAN_VERSION_MINOR;
89 data_cap->driver_version.patch = QWLAN_VERSION_PATCH;
90 data_cap->driver_version.build = QWLAN_VERSION_BUILD;
91 data_cap->allowed_dwell_time_min = config->nNeighborScanMinChanTime;
92 data_cap->allowed_dwell_time_max = config->nNeighborScanMaxChanTime;
93 data_cap->curr_dwell_time_min =
94 sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
95 adapter->sessionId);
96 data_cap->curr_dwell_time_max =
97 sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
98 adapter->sessionId);
99 data_cap->supported_bands = config->nBandCapability;
100
101 /* request for max num of channels */
Krishna Kumaar Natarajanc4f8a932016-04-16 13:51:42 +0530102 num_chan = OEM_CAP_MAX_NUM_CHANNELS;
Tushnim Bhattacharyyade1070d2017-03-09 13:23:55 -0800103 status = sme_get_cfg_valid_channels(
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800104 &chan_list[0], &num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530105 if (QDF_STATUS_SUCCESS != status) {
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800106 hdd_err("failed to get valid channel list, status: %d", status);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530107 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800108 return -EINVAL;
109 }
110
111 /* make sure num channels is not more than chan list array */
112 if (num_chan > OEM_CAP_MAX_NUM_CHANNELS) {
113 hdd_err("Num of channels-%d > length-%d of chan_list",
114 num_chan, OEM_CAP_MAX_NUM_CHANNELS);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530115 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800116 return -ENOMEM;
117 }
118
119 data_cap->num_channels = num_chan;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530120 qdf_mem_copy(data_cap->channel_list, chan_list,
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800121 sizeof(uint8_t) * num_chan);
122
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530123 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800124 return 0;
125}
126
127/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800128 * iw_get_oem_data_cap() - Get OEM Data Capabilities
129 * @dev: net device upon which the request was received
130 * @info: ioctl request information
131 * @wrqu: ioctl request data
132 * @extra: ioctl data payload
133 *
134 * This function gets the capability information for OEM Data Request
135 * and Response.
136 *
137 * Return: 0 for success, negative errno value on failure
138 */
139int iw_get_oem_data_cap(struct net_device *dev,
140 struct iw_request_info *info,
141 union iwreq_data *wrqu, char *extra)
142{
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800143 int status;
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700144 struct oem_data_cap oemDataCap = { {0} };
145 struct oem_data_cap *pHddOemDataCap;
Jeff Johnsonda47af82017-08-29 14:26:44 -0700146 struct hdd_adapter *pAdapter = (netdev_priv(dev));
Jeff Johnson1e3e3ee2017-08-28 11:47:40 -0700147 struct hdd_context *pHddContext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800148 int ret;
149
150 ENTER();
151
152 pHddContext = WLAN_HDD_GET_CTX(pAdapter);
153 ret = wlan_hdd_validate_context(pHddContext);
154 if (0 != ret)
155 return ret;
156
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800157 status = populate_oem_data_cap(pAdapter, &oemDataCap);
Krishna Kumaar Natarajanbc7e4942016-02-11 15:09:40 -0800158 if (0 != status) {
159 hdd_err("Failed to populate oem data capabilities");
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800160 return status;
Krishna Kumaar Natarajanbc7e4942016-02-11 15:09:40 -0800161 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800162
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700163 pHddOemDataCap = (struct oem_data_cap *) (extra);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800164 *pHddOemDataCap = oemDataCap;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165
166 EXIT();
167 return 0;
168}
169
170/**
171 * send_oem_reg_rsp_nlink_msg() - send oem registration response
172 *
173 * This function sends oem message to registered application process
174 *
175 * Return: none
176 */
177static void send_oem_reg_rsp_nlink_msg(void)
178{
179 struct sk_buff *skb;
180 struct nlmsghdr *nlh;
181 tAniMsgHdr *aniHdr;
182 uint8_t *buf;
183 uint8_t *numInterfaces;
184 uint8_t *deviceMode;
185 uint8_t *vdevId;
186 hdd_adapter_list_node_t *pAdapterNode = NULL;
187 hdd_adapter_list_node_t *pNext = NULL;
Jeff Johnsonda47af82017-08-29 14:26:44 -0700188 struct hdd_adapter *pAdapter = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530189 QDF_STATUS status = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800190
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700191 /* OEM msg is always to a specific process & cannot be a broadcast */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800192 if (p_hdd_ctx->oem_pid == 0) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700193 hdd_err("invalid dest pid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194 return;
195 }
196
197 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700198 if (skb == NULL)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800199 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800200
201 nlh = (struct nlmsghdr *)skb->data;
202 nlh->nlmsg_pid = 0; /* from kernel */
203 nlh->nlmsg_flags = 0;
204 nlh->nlmsg_seq = 0;
205 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
206 aniHdr = NLMSG_DATA(nlh);
207 aniHdr->type = ANI_MSG_APP_REG_RSP;
208
209 /* Fill message body:
210 * First byte will be number of interfaces, followed by
211 * two bytes for each interfaces
212 * - one byte for device mode
213 * - one byte for vdev id
214 */
215 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
216 numInterfaces = buf++;
217 *numInterfaces = 0;
218
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700219 /* Iterate through each adapter and fill device mode and vdev id */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220 status = hdd_get_front_adapter(p_hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530221 while ((QDF_STATUS_SUCCESS == status) && pAdapterNode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800222 pAdapter = pAdapterNode->pAdapter;
223 if (pAdapter) {
224 deviceMode = buf++;
225 vdevId = buf++;
226 *deviceMode = pAdapter->device_mode;
227 *vdevId = pAdapter->sessionId;
228 (*numInterfaces)++;
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800229 hdd_debug("numInterfaces: %d, deviceMode: %d, vdevId: %d",
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700230 *numInterfaces, *deviceMode,
231 *vdevId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 }
233 status = hdd_get_next_adapter(p_hdd_ctx, pAdapterNode, &pNext);
234 pAdapterNode = pNext;
235 }
236
237 aniHdr->length =
238 sizeof(uint8_t) + (*numInterfaces) * 2 * sizeof(uint8_t);
239 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
240
241 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
242
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800243 hdd_debug("sending App Reg Response length: %d to pid: %d",
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700244 aniHdr->length, p_hdd_ctx->oem_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800245
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530246 (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800247}
248
249/**
250 * send_oem_err_rsp_nlink_msg() - send oem error response
251 * @app_pid: PID of oem application process
252 * @error_code: response error code
253 *
254 * This function sends error response to oem app
255 *
256 * Return: none
257 */
258static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code)
259{
260 struct sk_buff *skb;
261 struct nlmsghdr *nlh;
262 tAniMsgHdr *aniHdr;
263 uint8_t *buf;
264
265 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700266 if (skb == NULL)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800267 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800268
269 nlh = (struct nlmsghdr *)skb->data;
270 nlh->nlmsg_pid = 0; /* from kernel */
271 nlh->nlmsg_flags = 0;
272 nlh->nlmsg_seq = 0;
273 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
274 aniHdr = NLMSG_DATA(nlh);
275 aniHdr->type = ANI_MSG_OEM_ERROR;
276 aniHdr->length = sizeof(uint8_t);
277 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + aniHdr->length);
278
279 /* message body will contain one byte of error code */
280 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
281 *buf = error_code;
282
283 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + aniHdr->length));
284
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800285 hdd_debug("sending oem error response to pid: %d", app_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800286
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530287 (void)nl_srv_ucast_oem(skb, app_pid, MSG_DONTWAIT);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800288}
289
290/**
291 * hdd_send_oem_data_rsp_msg() - send oem data response
Krishna Kumaar Natarajan73ea9f22016-06-30 18:38:47 -0700292 * @oem_data_rsp: the actual OEM Data Response message
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800293 *
294 * This function sends an OEM Data Response message to a registered
295 * application process over the netlink socket.
296 *
297 * Return: 0 for success, non zero for failure
298 */
Krishna Kumaar Natarajanc1fa17d2016-08-03 14:19:20 -0700299void hdd_send_oem_data_rsp_msg(struct oem_data_rsp *oem_data_rsp)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800300{
301 struct sk_buff *skb;
302 struct nlmsghdr *nlh;
Krishna Kumaar Natarajan73ea9f22016-06-30 18:38:47 -0700303 tAniMsgHdr *ani_hdr;
304 uint8_t *oem_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800305
Krishna Kumaar Natarajan73ea9f22016-06-30 18:38:47 -0700306 /*
307 * OEM message is always to a specific process and cannot be a broadcast
308 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800309 if (p_hdd_ctx->oem_pid == 0) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700310 hdd_err("invalid dest pid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800311 return;
312 }
313
Krishna Kumaar Natarajan73ea9f22016-06-30 18:38:47 -0700314 if (oem_data_rsp->rsp_len > OEM_DATA_RSP_SIZE) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700315 hdd_err("invalid length of Oem Data response");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800316 return;
317 }
318
319 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + OEM_DATA_RSP_SIZE),
320 GFP_KERNEL);
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700321 if (skb == NULL)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800322 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800323
324 nlh = (struct nlmsghdr *)skb->data;
325 nlh->nlmsg_pid = 0; /* from kernel */
326 nlh->nlmsg_flags = 0;
327 nlh->nlmsg_seq = 0;
328 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
Krishna Kumaar Natarajan73ea9f22016-06-30 18:38:47 -0700329 ani_hdr = NLMSG_DATA(nlh);
330 ani_hdr->type = ANI_MSG_OEM_DATA_RSP;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800331
Krishna Kumaar Natarajan73ea9f22016-06-30 18:38:47 -0700332 ani_hdr->length = oem_data_rsp->rsp_len;
333 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
334 oem_data = (uint8_t *) ((char *)ani_hdr + sizeof(tAniMsgHdr));
335 qdf_mem_copy(oem_data, oem_data_rsp->data, oem_data_rsp->rsp_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800336
Krishna Kumaar Natarajan73ea9f22016-06-30 18:38:47 -0700337 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800338
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800339 hdd_debug("sending Oem Data Response of len : %d to pid: %d",
Krishna Kumaar Natarajan73ea9f22016-06-30 18:38:47 -0700340 oem_data_rsp->rsp_len, p_hdd_ctx->oem_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800341
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530342 (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800343}
344
345/**
346 * oem_process_data_req_msg() - process oem data request
Krishna Kumaar Natarajanc5e06ac2016-06-30 16:49:19 -0700347 * @oem_data_len: Length to OEM Data buffer
348 * @oem_data: Pointer to OEM Data buffer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800349 *
350 * This function sends oem message to SME
351 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530352 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800353 */
Krishna Kumaar Natarajanc5e06ac2016-06-30 16:49:19 -0700354static QDF_STATUS oem_process_data_req_msg(int oem_data_len, char *oem_data)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800355{
Jeff Johnsonda47af82017-08-29 14:26:44 -0700356 struct hdd_adapter *adapter = NULL;
Krishna Kumaar Natarajanc1fa17d2016-08-03 14:19:20 -0700357 struct oem_data_req oem_data_req;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530358 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800359
360 /* for now, STA interface only */
Krishna Kumaar Natarajanc5e06ac2016-06-30 16:49:19 -0700361 adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE);
362 if (!adapter) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700363 hdd_err("No adapter for STA mode");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530364 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800365 }
366
Krishna Kumaar Natarajanc5e06ac2016-06-30 16:49:19 -0700367 if (!oem_data) {
368 hdd_err("oem_data is null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530369 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 }
371
Krishna Kumaar Natarajanc1fa17d2016-08-03 14:19:20 -0700372 qdf_mem_zero(&oem_data_req, sizeof(oem_data_req));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800373
Krishna Kumaar Natarajanc5e06ac2016-06-30 16:49:19 -0700374 oem_data_req.data = qdf_mem_malloc(oem_data_len);
375 if (!oem_data_req.data) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700376 hdd_err("malloc failed for data req buffer");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530377 return QDF_STATUS_E_NOMEM;
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800378 }
379
Krishna Kumaar Natarajanc5e06ac2016-06-30 16:49:19 -0700380 oem_data_req.data_len = oem_data_len;
381 qdf_mem_copy(oem_data_req.data, oem_data, oem_data_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800382
Krishna Kumaar Natarajanc5e06ac2016-06-30 16:49:19 -0700383 status = sme_oem_data_req(p_hdd_ctx->hHal, &oem_data_req);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800384
Krishna Kumaar Natarajanc5e06ac2016-06-30 16:49:19 -0700385 qdf_mem_free(oem_data_req.data);
386 oem_data_req.data = NULL;
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800387
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388 return status;
389}
390
391/**
Abhishek Singh1c676222016-05-09 14:20:28 +0530392 * update_channel_bw_info() - set bandwidth info for the chan
393 * @hdd_ctx: hdd context
394 * @chan: channel for which info are required
Yuanyuan Liud9db8252017-02-06 14:17:46 -0800395 * @chan_info: struct where the bandwidth info is filled
Abhishek Singh1c676222016-05-09 14:20:28 +0530396 *
397 * This function find the maximum bandwidth allowed, secondary
398 * channel offset and center freq for the channel as per regulatory
399 * domain and using these info calculate the phy mode for the
400 * channel.
401 *
402 * Return: void
403 */
Jeff Johnson1e3e3ee2017-08-28 11:47:40 -0700404void hdd_update_channel_bw_info(struct hdd_context *hdd_ctx,
Yuanyuan Liud9db8252017-02-06 14:17:46 -0800405 uint16_t chan, void *chan_info)
Abhishek Singh1c676222016-05-09 14:20:28 +0530406{
Amar Singhal5cccafe2017-02-15 12:42:58 -0800407 struct ch_params ch_params = {0};
Abhishek Singh1c676222016-05-09 14:20:28 +0530408 uint16_t sec_ch_2g = 0;
409 WLAN_PHY_MODE phy_mode;
410 uint32_t wni_dot11_mode;
Yuanyuan Liud9db8252017-02-06 14:17:46 -0800411 tHddChannelInfo *hdd_chan_info = chan_info;
Abhishek Singh1c676222016-05-09 14:20:28 +0530412
413 wni_dot11_mode = sme_get_wni_dot11_mode(hdd_ctx->hHal);
414
415 /* Passing CH_WIDTH_MAX will give the max bandwidth supported */
416 ch_params.ch_width = CH_WIDTH_MAX;
417
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700418 wlan_reg_set_channel_params(hdd_ctx->hdd_pdev, chan,
419 sec_ch_2g, &ch_params);
Abhishek Singh1c676222016-05-09 14:20:28 +0530420 if (ch_params.center_freq_seg0)
421 hdd_chan_info->band_center_freq1 =
422 cds_chan_to_freq(ch_params.center_freq_seg0);
423
Abhishek Singhd14304b2017-03-17 11:18:40 +0530424 if (ch_params.ch_width < CH_WIDTH_INVALID)
425 phy_mode = wma_chan_phy_mode(chan,
426 ch_params.ch_width, wni_dot11_mode);
427 else
428 /*
429 * If channel width is CH_WIDTH_INVALID, It mean channel is
430 * invalid and should not have been received in channel info
431 * req. Set invalid phymode in this case.
432 */
433 phy_mode = MODE_UNKNOWN;
Abhishek Singh1c676222016-05-09 14:20:28 +0530434
Abhishek Singhd14304b2017-03-17 11:18:40 +0530435 hdd_info("chan %d dot11_mode %d ch_width %d sec offset %d freq_seg0 %d phy_mode %d",
436 chan, wni_dot11_mode, ch_params.ch_width,
437 ch_params.sec_ch_offset,
438 hdd_chan_info->band_center_freq1, phy_mode);
439
Abhishek Singh1c676222016-05-09 14:20:28 +0530440 WMI_SET_CHANNEL_MODE(hdd_chan_info, phy_mode);
441}
442
443/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800444 * oem_process_channel_info_req_msg() - process oem channel_info request
445 * @numOfChannels: number of channels
446 * @chanList: list of channel information
447 *
448 * This function responds with channel info to oem process
449 *
450 * Return: 0 for success, non zero for failure
451 */
452static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList)
453{
454 struct sk_buff *skb;
455 struct nlmsghdr *nlh;
456 tAniMsgHdr *aniHdr;
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700457 struct hdd_channel_info *pHddChanInfo;
458 struct hdd_channel_info hddChanInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800459 uint8_t chanId;
460 uint32_t reg_info_1;
461 uint32_t reg_info_2;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530462 QDF_STATUS status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800463 int i;
464 uint8_t *buf;
465
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700466 /* OEM msg is always to a specific process and cannot be a broadcast */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800467 if (p_hdd_ctx->oem_pid == 0) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700468 hdd_err("invalid dest pid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800469 return -EPERM;
470 }
471
472 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) +
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700473 numOfChannels * sizeof(*pHddChanInfo)),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 GFP_KERNEL);
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700475 if (skb == NULL)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 return -ENOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477
478 nlh = (struct nlmsghdr *)skb->data;
479 nlh->nlmsg_pid = 0; /* from kernel */
480 nlh->nlmsg_flags = 0;
481 nlh->nlmsg_seq = 0;
482 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
483 aniHdr = NLMSG_DATA(nlh);
484 aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP;
485
486 aniHdr->length =
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700487 sizeof(uint8_t) + numOfChannels * sizeof(*pHddChanInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800488 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
489
490 /* First byte of message body will have num of channels */
491 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
492 *buf++ = numOfChannels;
493
494 /* Next follows channel info struct for each channel id.
495 * If chan id is wrong or SME returns failure for a channel
496 * then fill in 0 in channel info for that particular channel
497 */
498 for (i = 0; i < numOfChannels; i++) {
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700499 pHddChanInfo = (struct hdd_channel_info *) ((char *)buf +
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800500 i *
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700501 sizeof(*pHddChanInfo));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502
503 chanId = chanList[i];
504 status = sme_get_reg_info(p_hdd_ctx->hHal, chanId,
505 &reg_info_1, &reg_info_2);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530506 if (QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800507 /* copy into hdd chan info struct */
508 hddChanInfo.chan_id = chanId;
509 hddChanInfo.reserved0 = 0;
510 hddChanInfo.mhz = cds_chan_to_freq(chanId);
511 hddChanInfo.band_center_freq1 = hddChanInfo.mhz;
512 hddChanInfo.band_center_freq2 = 0;
513
514 hddChanInfo.info = 0;
515 if (CHANNEL_STATE_DFS ==
Kiran Kumar Lokerea3de2262017-04-12 12:15:04 -0700516 wlan_reg_get_channel_state(p_hdd_ctx->hdd_pdev,
517 chanId))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800518 WMI_SET_CHANNEL_FLAG(&hddChanInfo,
519 WMI_CHAN_FLAG_DFS);
Abhishek Singh1c676222016-05-09 14:20:28 +0530520
521 hdd_update_channel_bw_info(p_hdd_ctx,
522 chanId, &hddChanInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800523 hddChanInfo.reg_info_1 = reg_info_1;
524 hddChanInfo.reg_info_2 = reg_info_2;
525 } else {
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700526 /* channel info is not returned, fill in zeros in
527 * channel info struct
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800528 */
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700529 hdd_debug("sme_get_reg_info failed for chan: %d, fill 0s",
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700530 chanId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800531 hddChanInfo.chan_id = chanId;
532 hddChanInfo.reserved0 = 0;
533 hddChanInfo.mhz = 0;
534 hddChanInfo.band_center_freq1 = 0;
535 hddChanInfo.band_center_freq2 = 0;
536 hddChanInfo.info = 0;
537 hddChanInfo.reg_info_1 = 0;
538 hddChanInfo.reg_info_2 = 0;
539 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530540 qdf_mem_copy(pHddChanInfo, &hddChanInfo,
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700541 sizeof(*pHddChanInfo));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542 }
543
544 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
545
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800546 hdd_debug("sending channel info resp for num channels (%d) to pid (%d)",
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700547 numOfChannels, p_hdd_ctx->oem_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800548
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530549 (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800550
551 return 0;
552}
553
554/**
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800555 * oem_process_set_cap_req_msg() - process oem set capability request
556 * @oem_cap_len: Length of OEM capability
557 * @oem_cap: Pointer to OEM capability buffer
558 * @app_pid: process ID, to which rsp message is to be sent
559 *
560 * This function sends oem message to SME
561 *
562 * Return: error code
563 */
564static int oem_process_set_cap_req_msg(int oem_cap_len,
565 char *oem_cap, int32_t app_pid)
566{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530567 QDF_STATUS status;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800568 int error_code;
569 struct sk_buff *skb;
570 struct nlmsghdr *nlh;
571 tAniMsgHdr *ani_hdr;
572 uint8_t *buf;
573
574 if (!oem_cap) {
575 hdd_err("oem_cap is null");
576 return -EINVAL;
577 }
578
579 status = sme_oem_update_capability(p_hdd_ctx->hHal,
580 (struct sme_oem_capability *)oem_cap);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530581 if (!QDF_IS_STATUS_SUCCESS(status))
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800582 hdd_err("error updating rm capability, status: %d", status);
Anurag Chouhanc5548422016-02-24 18:33:27 +0530583 error_code = qdf_status_to_os_return(status);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800584
585 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700586 if (skb == NULL)
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800587 return -ENOMEM;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800588
589 nlh = (struct nlmsghdr *)skb->data;
590 nlh->nlmsg_pid = 0; /* from kernel */
591 nlh->nlmsg_flags = 0;
592 nlh->nlmsg_seq = 0;
593 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
594 ani_hdr = NLMSG_DATA(nlh);
595 ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP;
596 /* 64 bit alignment */
597 ani_hdr->length = sizeof(error_code);
598 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length);
599
600 /* message body will contain only status code */
601 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530602 qdf_mem_copy(buf, &error_code, ani_hdr->length);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800603
604 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length));
605
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800606 hdd_debug("sending oem response to pid %d", app_pid);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800607
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530608 (void)nl_srv_ucast_oem(skb, app_pid, MSG_DONTWAIT);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800609
610 return error_code;
611}
612
613/**
614 * oem_process_get_cap_req_msg() - process oem get capability request
615 *
616 * This function process the get capability request from OEM and responds
617 * with the capability.
618 *
619 * Return: error code
620 */
621static int oem_process_get_cap_req_msg(void)
622{
623 int error_code;
624 struct oem_get_capability_rsp *cap_rsp;
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700625 struct oem_data_cap data_cap = { {0} };
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800626 struct sme_oem_capability oem_cap;
Jeff Johnsonda47af82017-08-29 14:26:44 -0700627 struct hdd_adapter *adapter;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800628 struct sk_buff *skb;
629 struct nlmsghdr *nlh;
630 tAniMsgHdr *ani_hdr;
631 uint8_t *buf;
632
633 /* for now, STA interface only */
Krunal Sonibe766b02016-03-10 13:00:44 -0800634 adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800635 if (!adapter) {
636 hdd_err("No adapter for STA mode");
637 return -EINVAL;
638 }
639
640 error_code = populate_oem_data_cap(adapter, &data_cap);
641 if (0 != error_code)
642 return error_code;
643
644 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)),
645 GFP_KERNEL);
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700646 if (skb == NULL)
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800647 return -ENOMEM;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800648
649 nlh = (struct nlmsghdr *)skb->data;
650 nlh->nlmsg_pid = 0; /* from kernel */
651 nlh->nlmsg_flags = 0;
652 nlh->nlmsg_seq = 0;
653 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
654 ani_hdr = NLMSG_DATA(nlh);
655 ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP;
656
657 ani_hdr->length = sizeof(*cap_rsp);
658 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
659
660 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530661 qdf_mem_copy(buf, &data_cap, sizeof(data_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800662
663 buf = (char *) buf + sizeof(data_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530664 qdf_mem_zero(&oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800665 sme_oem_get_capability(p_hdd_ctx->hHal, &oem_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530666 qdf_mem_copy(buf, &oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800667
668 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
669 hdd_info("send rsp to oem-pid:%d for get_capability",
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700670 p_hdd_ctx->oem_pid);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800671
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530672 (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800673 return 0;
674}
675
676/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800677 * hdd_send_peer_status_ind_to_oem_app() -
Abhishek Singh1c676222016-05-09 14:20:28 +0530678 * Function to send peer status to a registered application
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800679 * @peerMac: MAC address of peer
680 * @peerStatus: ePeerConnected or ePeerDisconnected
681 * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0
682 * @sessionId: SME session id, i.e. vdev_id
683 * @chan_info: operating channel information
Abhishek Singh1c676222016-05-09 14:20:28 +0530684 * @dev_mode: dev mode for which indication is sent
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800685 *
686 * Return: none
687 */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530688void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800689 uint8_t peerStatus,
690 uint8_t peerTimingMeasCap,
691 uint8_t sessionId,
Abhishek Singh1c676222016-05-09 14:20:28 +0530692 tSirSmeChanInfo *chan_info,
693 enum tQDF_ADAPTER_MODE dev_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800694{
695 struct sk_buff *skb;
696 struct nlmsghdr *nlh;
697 tAniMsgHdr *aniHdr;
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700698 struct peer_status_info *pPeerInfo;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800699
700 if (!p_hdd_ctx || !p_hdd_ctx->hHal) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700701 hdd_err("Either HDD Ctx is null or Hal Ctx is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800702 return;
703 }
704
705 /* check if oem app has registered and pid is valid */
706 if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700707 hdd_info("OEM app is not registered(%d) or pid is invalid(%d)",
708 p_hdd_ctx->oem_app_registered,
709 p_hdd_ctx->oem_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800710 return;
711 }
712
713 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) +
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700714 sizeof(*pPeerInfo)),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800715 GFP_KERNEL);
Srinivas Girigowda75af3d12017-03-25 11:17:46 -0700716 if (skb == NULL)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800717 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800718
719 nlh = (struct nlmsghdr *)skb->data;
720 nlh->nlmsg_pid = 0; /* from kernel */
721 nlh->nlmsg_flags = 0;
722 nlh->nlmsg_seq = 0;
723 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
724 aniHdr = NLMSG_DATA(nlh);
725 aniHdr->type = ANI_MSG_PEER_STATUS_IND;
726
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700727 aniHdr->length = sizeof(*pPeerInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800728 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
729
Srinivas Girigowdacaac83f2017-03-25 00:44:55 -0700730 pPeerInfo = (struct peer_status_info *) ((char *)aniHdr + sizeof(tAniMsgHdr));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800731
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530732 qdf_mem_copy(pPeerInfo->peer_mac_addr, peerMac->bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800733 sizeof(peerMac->bytes));
734 pPeerInfo->peer_status = peerStatus;
735 pPeerInfo->vdev_id = sessionId;
736 pPeerInfo->peer_capability = peerTimingMeasCap;
737 pPeerInfo->reserved0 = 0;
Abhishek Singh1c676222016-05-09 14:20:28 +0530738 /* Set 0th bit of reserved0 for STA mode */
739 if (QDF_STA_MODE == dev_mode)
740 pPeerInfo->reserved0 |= 0x01;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800741
742 if (chan_info) {
743 pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id;
744 pPeerInfo->peer_chan_info.reserved0 = 0;
745 pPeerInfo->peer_chan_info.mhz = chan_info->mhz;
746 pPeerInfo->peer_chan_info.band_center_freq1 =
747 chan_info->band_center_freq1;
748 pPeerInfo->peer_chan_info.band_center_freq2 =
749 chan_info->band_center_freq2;
750 pPeerInfo->peer_chan_info.info = chan_info->info;
751 pPeerInfo->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
752 pPeerInfo->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
753 } else {
754 pPeerInfo->peer_chan_info.chan_id = 0;
755 pPeerInfo->peer_chan_info.reserved0 = 0;
756 pPeerInfo->peer_chan_info.mhz = 0;
757 pPeerInfo->peer_chan_info.band_center_freq1 = 0;
758 pPeerInfo->peer_chan_info.band_center_freq2 = 0;
759 pPeerInfo->peer_chan_info.info = 0;
760 pPeerInfo->peer_chan_info.reg_info_1 = 0;
761 pPeerInfo->peer_chan_info.reg_info_2 = 0;
762 }
763 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
764
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700765 hdd_info("sending peer " MAC_ADDRESS_STR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800766 " status(%d), peerTimingMeasCap(%d), vdevId(%d), chanId(%d)"
767 " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d),"
768 " info (0x%x), frequency (%d),reg info 1 (0x%x),"
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700769 " reg info 2 (0x%x)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800770 MAC_ADDR_ARRAY(peerMac->bytes),
771 peerStatus, peerTimingMeasCap,
772 sessionId, pPeerInfo->peer_chan_info.chan_id,
773 p_hdd_ctx->oem_pid,
774 pPeerInfo->peer_chan_info.band_center_freq1,
775 pPeerInfo->peer_chan_info.band_center_freq2,
776 pPeerInfo->peer_chan_info.info,
777 pPeerInfo->peer_chan_info.mhz,
778 pPeerInfo->peer_chan_info.reg_info_1,
779 pPeerInfo->peer_chan_info.reg_info_2);
780
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530781 (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800782}
783
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530784/**
785 * oem_app_reg_req_handler() - function to handle APP registration request
786 * from userspace
787 * @hdd_ctx: handle to HDD context
788 * @msg_hdr: pointer to ANI message header
789 * @pid: Process ID
790 *
791 * Return: 0 if success, error code otherwise
792 */
Jeff Johnson82797b62017-08-11 15:31:27 -0700793static int oem_app_reg_req_handler(struct hdd_context *hdd_ctx,
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530794 tAniMsgHdr *msg_hdr, int pid)
795{
796 char *sign_str = NULL;
797
798 /* Registration request is only allowed for Qualcomm Application */
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800799 hdd_debug("Received App Req Req from App pid: %d len: %d",
800 pid, msg_hdr->length);
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530801
802 sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr));
803 if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) &&
804 (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR,
805 OEM_APP_SIGNATURE_LEN))) {
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800806 hdd_debug("Valid App Req Req from oem app pid: %d", pid);
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530807
808 hdd_ctx->oem_app_registered = true;
809 hdd_ctx->oem_pid = pid;
810 send_oem_reg_rsp_nlink_msg();
811 } else {
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800812 hdd_err("Invalid signature in App Reg Req from pid: %d", pid);
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530813 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_SIGNATURE);
814 return -EPERM;
815 }
816
817 return 0;
818}
819
820/**
821 * oem_data_req_handler() - function to handle data_req from userspace
822 * @hdd_ctx: handle to HDD context
823 * @msg_hdr: pointer to ANI message header
824 * @pid: Process ID
825 *
826 * Return: 0 if success, error code otherwise
827 */
Jeff Johnson82797b62017-08-11 15:31:27 -0700828static int oem_data_req_handler(struct hdd_context *hdd_ctx,
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530829 tAniMsgHdr *msg_hdr, int pid)
830{
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800831 hdd_debug("Received Oem Data Request length: %d from pid: %d",
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530832 msg_hdr->length, pid);
833
834 if ((!hdd_ctx->oem_app_registered) ||
835 (pid != hdd_ctx->oem_pid)) {
836 /* either oem app is not registered yet or pid is different */
837 hdd_err("OEM DataReq: app not registered(%d) or incorrect pid(%d)",
838 hdd_ctx->oem_app_registered, pid);
839 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED);
840 return -EPERM;
841 }
842
843 if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) {
844 hdd_err("Invalid length (%d) in Oem Data Request",
845 msg_hdr->length);
846 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH);
847 return -EPERM;
848 }
849
850 oem_process_data_req_msg(msg_hdr->length,
851 (char *) ((char *)msg_hdr +
852 sizeof(tAniMsgHdr)));
853
854 return 0;
855}
856
857/**
858 * oem_chan_info_req_handler() - function to handle chan_info_req from userspace
859 * @hdd_ctx: handle to HDD context
860 * @msg_hdr: pointer to ANI message header
861 * @pid: Process ID
862 *
863 * Return: 0 if success, error code otherwise
864 */
Jeff Johnson82797b62017-08-11 15:31:27 -0700865static int oem_chan_info_req_handler(struct hdd_context *hdd_ctx,
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530866 tAniMsgHdr *msg_hdr, int pid)
867{
Srinivas Girigowdac06543c2017-03-09 15:10:03 -0800868 hdd_debug("Received channel info request, num channel(%d) from pid: %d",
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530869 msg_hdr->length, pid);
870
871 if ((!hdd_ctx->oem_app_registered) ||
872 (pid != hdd_ctx->oem_pid)) {
873 /* either oem app is not registered yet or pid is different */
874 hdd_err("Chan InfoReq: app not registered(%d) or incorrect pid(%d)",
875 hdd_ctx->oem_app_registered, pid);
876 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED);
877 return -EPERM;
878 }
879
880 /* message length contains list of channel ids */
881 if ((!msg_hdr->length) ||
882 (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) {
883 hdd_err("Invalid length (%d) in channel info request",
884 msg_hdr->length);
885 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH);
886 return -EPERM;
887 }
888 oem_process_channel_info_req_msg(msg_hdr->length,
889 (char *)((char *)msg_hdr + sizeof(tAniMsgHdr)));
890
891 return 0;
892}
893
894/**
895 * oem_set_cap_req_handler() - function to handle set_cap_req from userspace
896 * @hdd_ctx: handle to HDD context
897 * @msg_hdr: pointer to ANI message header
898 * @pid: Process ID
899 *
900 * Return: 0 if success, error code otherwise
901 */
Jeff Johnson82797b62017-08-11 15:31:27 -0700902static int oem_set_cap_req_handler(struct hdd_context *hdd_ctx,
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530903 tAniMsgHdr *msg_hdr, int pid)
904{
905 hdd_info("Received set oem cap req of length:%d from pid: %d",
906 msg_hdr->length, pid);
907
908 if ((!hdd_ctx->oem_app_registered) ||
909 (pid != hdd_ctx->oem_pid)) {
910 /* oem app is not registered yet or pid is different */
911 hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)",
912 hdd_ctx->oem_app_registered, pid);
913 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED);
914 return -EPERM;
915 }
916
917 if ((!msg_hdr->length) ||
918 (sizeof(struct sme_oem_capability) < msg_hdr->length)) {
919 hdd_err("Invalid length (%d) in set_oem_capability",
920 msg_hdr->length);
921 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH);
922 return -EPERM;
923 }
924
925 oem_process_set_cap_req_msg(msg_hdr->length, (char *)
926 ((char *)msg_hdr + sizeof(tAniMsgHdr)),
927 pid);
928 return 0;
929}
930
931/**
932 * oem_get_cap_req_handler() - function to handle get_cap_req from userspace
933 * @hdd_ctx: handle to HDD context
934 * @msg_hdr: pointer to ANI message header
935 * @pid: Process ID
936 *
937 * Return: 0 if success, error code otherwise
938 */
Jeff Johnson82797b62017-08-11 15:31:27 -0700939static int oem_get_cap_req_handler(struct hdd_context *hdd_ctx,
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +0530940 tAniMsgHdr *msg_hdr, int pid)
941{
942 hdd_info("Rcvd get oem capability req - length:%d from pid: %d",
943 msg_hdr->length, pid);
944
945 if ((!hdd_ctx->oem_app_registered) ||
946 (pid != hdd_ctx->oem_pid)) {
947 /* oem app is not registered yet or pid is different */
948 hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)",
949 hdd_ctx->oem_app_registered, pid);
950 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED);
951 return -EPERM;
952 }
953
954 oem_process_get_cap_req_msg();
955 return 0;
956}
957
958/**
959 * oem_request_dispatcher() - OEM command dispatcher API
960 * @msg_hdr: ANI Message Header
961 * @pid: process id
962 *
963 * This API is used to dispatch the command from OEM depending
964 * on the type of the message received.
965 *
966 * Return: None
967 */
968static void oem_request_dispatcher(tAniMsgHdr *msg_hdr, int pid)
969{
970 switch (msg_hdr->type) {
971 case ANI_MSG_APP_REG_REQ:
972 oem_app_reg_req_handler(p_hdd_ctx, msg_hdr, pid);
973 break;
974
975 case ANI_MSG_OEM_DATA_REQ:
976 oem_data_req_handler(p_hdd_ctx, msg_hdr, pid);
977 break;
978
979 case ANI_MSG_CHANNEL_INFO_REQ:
980 oem_chan_info_req_handler(p_hdd_ctx, msg_hdr, pid);
981 break;
982
983 case ANI_MSG_SET_OEM_CAP_REQ:
984 oem_set_cap_req_handler(p_hdd_ctx, msg_hdr, pid);
985 break;
986
987 case ANI_MSG_GET_OEM_CAP_REQ:
988 oem_get_cap_req_handler(p_hdd_ctx, msg_hdr, pid);
989 break;
990
991 default:
992 hdd_err("Received Invalid message type (%d), length (%d)",
993 msg_hdr->type, msg_hdr->length);
994 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_TYPE);
995 }
996}
997
998#ifdef CNSS_GENL
999/**
1000 * oem_cmd_handler() - API to handle OEM commands
1001 * @data: Pointer to data
1002 * @data_len: length of the received data
1003 * @ctx: Pointer to the context
1004 * @pid: Process id
1005 *
1006 * This API handles the command from OEM application from user space and
1007 * send back event to user space if necessary.
1008 *
1009 * Return: None
1010 */
1011static void oem_cmd_handler(const void *data, int data_len, void *ctx, int pid)
1012{
1013 tAniMsgHdr *msg_hdr;
Jeff Johnson1818a652017-06-01 13:52:35 -07001014 int msg_len;
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05301015 int ret;
1016 struct nlattr *tb[CLD80211_ATTR_MAX + 1];
1017
1018 ret = wlan_hdd_validate_context(p_hdd_ctx);
1019 if (ret) {
1020 hdd_err("hdd ctx validate fails");
1021 return;
1022 }
1023
Jeff Johnson1818a652017-06-01 13:52:35 -07001024 /*
1025 * audit note: it is ok to pass a NULL policy here since only
1026 * one attribute is parsed and it is explicitly validated
1027 */
Dustin Brown3fb15042017-08-15 15:54:49 -07001028 if (hdd_nla_parse(tb, CLD80211_ATTR_MAX, data, data_len, NULL)) {
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05301029 hdd_err("Invalid ATTR");
1030 return;
1031 }
1032
1033 if (!tb[CLD80211_ATTR_DATA]) {
1034 hdd_err("attr ATTR_DATA failed");
1035 return;
1036 }
1037
Jeff Johnson1818a652017-06-01 13:52:35 -07001038 msg_len = nla_len(tb[CLD80211_ATTR_DATA]);
1039 if (msg_len < sizeof(*msg_hdr)) {
1040 hdd_err("runt ATTR_DATA size %d", msg_len);
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05301041 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_NULL_MESSAGE_HEADER);
1042 return;
1043 }
Jeff Johnson1818a652017-06-01 13:52:35 -07001044
1045 msg_hdr = nla_data(tb[CLD80211_ATTR_DATA]);
1046 if (msg_len < (sizeof(*msg_hdr) + msg_hdr->length)) {
1047 hdd_err("Invalid nl msg len %d, msg hdr len %d",
1048 msg_len, msg_hdr->length);
1049 send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH);
1050 return;
1051 }
1052
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05301053 oem_request_dispatcher(msg_hdr, pid);
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05301054}
1055
1056/**
1057 * oem_activate_service() - API to register the oem command handler
1058 * @hdd_ctx: Pointer to HDD Context
1059 *
1060 * This API is used to register the oem app command handler. Argument
1061 * @pAdapter is given for prototype compatibility with legacy code.
1062 *
1063 * Return: 0
1064 */
Jeff Johnson82797b62017-08-11 15:31:27 -07001065int oem_activate_service(struct hdd_context *hdd_ctx)
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05301066{
1067 p_hdd_ctx = hdd_ctx;
1068 register_cld_cmd_cb(WLAN_NL_MSG_OEM, oem_cmd_handler, NULL);
1069 return 0;
1070}
1071#else
1072
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001073/*
1074 * Callback function invoked by Netlink service for all netlink
1075 * messages (from user space) addressed to WLAN_NL_MSG_OEM
1076 */
1077
1078/**
1079 * oem_msg_callback() - callback invoked by netlink service
1080 * @skb: skb with netlink message
1081 *
1082 * This function gets invoked by netlink service when a message
1083 * is received from user space addressed to WLAN_NL_MSG_OEM
1084 *
1085 * Return: zero on success
1086 * On error, error number will be returned.
1087 */
1088static int oem_msg_callback(struct sk_buff *skb)
1089{
1090 struct nlmsghdr *nlh;
1091 tAniMsgHdr *msg_hdr;
1092 int ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001093
Srinivas Girigowda75af3d12017-03-25 11:17:46 -07001094 nlh = (struct nlmsghdr *)skb->data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001095 if (!nlh) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -07001096 hdd_err("Netlink header null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001097 return -EPERM;
1098 }
1099
1100 ret = wlan_hdd_validate_context(p_hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +05301101 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001102 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001103
1104 msg_hdr = NLMSG_DATA(nlh);
1105
1106 if (!msg_hdr) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -07001107 hdd_err("Message header null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001108 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
1109 OEM_ERR_NULL_MESSAGE_HEADER);
1110 return -EPERM;
1111 }
1112
1113 if (nlh->nlmsg_len <
1114 NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -07001115 hdd_err("Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)",
1116 nlh->nlmsg_len, msg_hdr->length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001117 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
1118 OEM_ERR_INVALID_MESSAGE_LENGTH);
1119 return -EPERM;
1120 }
1121
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05301122 oem_request_dispatcher(msg_hdr, nlh->nlmsg_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001123 return 0;
1124}
1125
1126static int __oem_msg_callback(struct sk_buff *skb)
1127{
1128 int ret;
1129
1130 cds_ssr_protect(__func__);
1131 ret = oem_msg_callback(skb);
1132 cds_ssr_unprotect(__func__);
1133
1134 return ret;
1135}
1136
1137/**
1138 * oem_activate_service() - Activate oem message handler
1139 * @hdd_ctx: pointer to global HDD context
1140 *
1141 * This function registers a handler to receive netlink message from
1142 * an OEM application process.
1143 *
1144 * Return: zero on success
1145 * On error, error number will be returned.
1146 */
Jeff Johnson82797b62017-08-11 15:31:27 -07001147int oem_activate_service(struct hdd_context *hdd_ctx)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001148{
1149 p_hdd_ctx = hdd_ctx;
1150
1151 /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
1152 return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback);
1153}
Selvaraj, Sridhar046d77d2017-03-07 14:53:13 +05301154#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001155#endif