blob: 0112f694fe0c540894466b3ad34acc6e7c9d0684 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -08002 * Copyright (c) 2012-2016 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"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080048
49static struct hdd_context_s *p_hdd_ctx;
50
51/**
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080052 * populate_oem_data_cap() - populate oem capabilities
53 * @adapter: device adapter
54 * @data_cap: pointer to populate the capabilities
55 *
56 * Return: error code
57 */
58static int populate_oem_data_cap(hdd_adapter_t *adapter,
59 t_iw_oem_data_cap *data_cap)
60{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +053061 QDF_STATUS status = QDF_STATUS_E_FAILURE;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080062 struct hdd_config *config;
63 uint32_t num_chan;
64 uint8_t *chan_list;
65 hdd_context_t *hdd_ctx = adapter->pHddCtx;
66
67 config = hdd_ctx->config;
68 if (!config) {
69 hdd_err("HDD configuration is null");
70 return -EINVAL;
71 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +053072 chan_list = qdf_mem_malloc(sizeof(uint8_t) * OEM_CAP_MAX_NUM_CHANNELS);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080073 if (NULL == chan_list) {
74 hdd_err("Memory allocation failed");
75 return -ENOMEM;
76 }
77
78 strlcpy(data_cap->oem_target_signature, OEM_TARGET_SIGNATURE,
79 OEM_TARGET_SIGNATURE_LEN);
80 data_cap->oem_target_type = hdd_ctx->target_type;
81 data_cap->oem_fw_version = hdd_ctx->target_fw_version;
82 data_cap->driver_version.major = QWLAN_VERSION_MAJOR;
83 data_cap->driver_version.minor = QWLAN_VERSION_MINOR;
84 data_cap->driver_version.patch = QWLAN_VERSION_PATCH;
85 data_cap->driver_version.build = QWLAN_VERSION_BUILD;
86 data_cap->allowed_dwell_time_min = config->nNeighborScanMinChanTime;
87 data_cap->allowed_dwell_time_max = config->nNeighborScanMaxChanTime;
88 data_cap->curr_dwell_time_min =
89 sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
90 adapter->sessionId);
91 data_cap->curr_dwell_time_max =
92 sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
93 adapter->sessionId);
94 data_cap->supported_bands = config->nBandCapability;
95
96 /* request for max num of channels */
97 num_chan = WNI_CFG_VALID_CHANNEL_LIST_LEN;
98 status = sme_get_cfg_valid_channels(hdd_ctx->hHal,
99 &chan_list[0], &num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530100 if (QDF_STATUS_SUCCESS != status) {
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800101 hdd_err("failed to get valid channel list, status: %d", status);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530102 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800103 return -EINVAL;
104 }
105
106 /* make sure num channels is not more than chan list array */
107 if (num_chan > OEM_CAP_MAX_NUM_CHANNELS) {
108 hdd_err("Num of channels-%d > length-%d of chan_list",
109 num_chan, OEM_CAP_MAX_NUM_CHANNELS);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530110 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800111 return -ENOMEM;
112 }
113
114 data_cap->num_channels = num_chan;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530115 qdf_mem_copy(data_cap->channel_list, chan_list,
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800116 sizeof(uint8_t) * num_chan);
117
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530118 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800119 return 0;
120}
121
122/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800123 * iw_get_oem_data_cap() - Get OEM Data Capabilities
124 * @dev: net device upon which the request was received
125 * @info: ioctl request information
126 * @wrqu: ioctl request data
127 * @extra: ioctl data payload
128 *
129 * This function gets the capability information for OEM Data Request
130 * and Response.
131 *
132 * Return: 0 for success, negative errno value on failure
133 */
134int iw_get_oem_data_cap(struct net_device *dev,
135 struct iw_request_info *info,
136 union iwreq_data *wrqu, char *extra)
137{
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800138 int status;
139 t_iw_oem_data_cap oemDataCap = { {0} };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140 t_iw_oem_data_cap *pHddOemDataCap;
141 hdd_adapter_t *pAdapter = (netdev_priv(dev));
142 hdd_context_t *pHddContext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143 int ret;
144
145 ENTER();
146
147 pHddContext = WLAN_HDD_GET_CTX(pAdapter);
148 ret = wlan_hdd_validate_context(pHddContext);
149 if (0 != ret)
150 return ret;
151
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800152 status = populate_oem_data_cap(pAdapter, &oemDataCap);
Krishna Kumaar Natarajanbc7e4942016-02-11 15:09:40 -0800153 if (0 != status) {
154 hdd_err("Failed to populate oem data capabilities");
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800155 return status;
Krishna Kumaar Natarajanbc7e4942016-02-11 15:09:40 -0800156 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800157
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800158 pHddOemDataCap = (t_iw_oem_data_cap *) (extra);
159 *pHddOemDataCap = oemDataCap;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800160
161 EXIT();
162 return 0;
163}
164
165/**
166 * send_oem_reg_rsp_nlink_msg() - send oem registration response
167 *
168 * This function sends oem message to registered application process
169 *
170 * Return: none
171 */
172static void send_oem_reg_rsp_nlink_msg(void)
173{
174 struct sk_buff *skb;
175 struct nlmsghdr *nlh;
176 tAniMsgHdr *aniHdr;
177 uint8_t *buf;
178 uint8_t *numInterfaces;
179 uint8_t *deviceMode;
180 uint8_t *vdevId;
181 hdd_adapter_list_node_t *pAdapterNode = NULL;
182 hdd_adapter_list_node_t *pNext = NULL;
183 hdd_adapter_t *pAdapter = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530184 QDF_STATUS status = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800185
186 /* OEM message is always to a specific process and cannot be a broadcast */
187 if (p_hdd_ctx->oem_pid == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530188 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800189 "%s: invalid dest pid", __func__);
190 return;
191 }
192
193 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
194 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530195 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800196 "%s: alloc_skb failed", __func__);
197 return;
198 }
199
200 nlh = (struct nlmsghdr *)skb->data;
201 nlh->nlmsg_pid = 0; /* from kernel */
202 nlh->nlmsg_flags = 0;
203 nlh->nlmsg_seq = 0;
204 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
205 aniHdr = NLMSG_DATA(nlh);
206 aniHdr->type = ANI_MSG_APP_REG_RSP;
207
208 /* Fill message body:
209 * First byte will be number of interfaces, followed by
210 * two bytes for each interfaces
211 * - one byte for device mode
212 * - one byte for vdev id
213 */
214 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
215 numInterfaces = buf++;
216 *numInterfaces = 0;
217
218 /* Iterate through each of the adapters and fill device mode and vdev id */
219 status = hdd_get_front_adapter(p_hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530220 while ((QDF_STATUS_SUCCESS == status) && pAdapterNode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800221 pAdapter = pAdapterNode->pAdapter;
222 if (pAdapter) {
223 deviceMode = buf++;
224 vdevId = buf++;
225 *deviceMode = pAdapter->device_mode;
226 *vdevId = pAdapter->sessionId;
227 (*numInterfaces)++;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530228 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800229 "%s: numInterfaces: %d, deviceMode: %d, vdevId: %d",
230 __func__, *numInterfaces, *deviceMode,
231 *vdevId);
232 }
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
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530243 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800244 "%s: sending App Reg Response length (%d) to process pid (%d)",
245 __func__, aniHdr->length, p_hdd_ctx->oem_pid);
246
247 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
248
249 return;
250}
251
252/**
253 * send_oem_err_rsp_nlink_msg() - send oem error response
254 * @app_pid: PID of oem application process
255 * @error_code: response error code
256 *
257 * This function sends error response to oem app
258 *
259 * Return: none
260 */
261static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code)
262{
263 struct sk_buff *skb;
264 struct nlmsghdr *nlh;
265 tAniMsgHdr *aniHdr;
266 uint8_t *buf;
267
268 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
269 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530270 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800271 "%s: alloc_skb failed", __func__);
272 return;
273 }
274
275 nlh = (struct nlmsghdr *)skb->data;
276 nlh->nlmsg_pid = 0; /* from kernel */
277 nlh->nlmsg_flags = 0;
278 nlh->nlmsg_seq = 0;
279 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
280 aniHdr = NLMSG_DATA(nlh);
281 aniHdr->type = ANI_MSG_OEM_ERROR;
282 aniHdr->length = sizeof(uint8_t);
283 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + aniHdr->length);
284
285 /* message body will contain one byte of error code */
286 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
287 *buf = error_code;
288
289 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + aniHdr->length));
290
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530291 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800292 "%s: sending oem error response to process pid (%d)",
293 __func__, app_pid);
294
295 (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
296
297 return;
298}
299
300/**
301 * hdd_send_oem_data_rsp_msg() - send oem data response
302 * @length: length of the OEM Data Response message
303 * @oemDataRsp: the actual OEM Data Response message
304 *
305 * This function sends an OEM Data Response message to a registered
306 * application process over the netlink socket.
307 *
308 * Return: 0 for success, non zero for failure
309 */
310void hdd_send_oem_data_rsp_msg(int length, uint8_t *oemDataRsp)
311{
312 struct sk_buff *skb;
313 struct nlmsghdr *nlh;
314 tAniMsgHdr *aniHdr;
315 uint8_t *oemData;
316
317 /* OEM message is always to a specific process and cannot be a broadcast */
318 if (p_hdd_ctx->oem_pid == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530319 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800320 "%s: invalid dest pid", __func__);
321 return;
322 }
323
324 if (length > OEM_DATA_RSP_SIZE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530325 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800326 "%s: invalid length of Oem Data response", __func__);
327 return;
328 }
329
330 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + OEM_DATA_RSP_SIZE),
331 GFP_KERNEL);
332 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530333 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800334 "%s: alloc_skb failed", __func__);
335 return;
336 }
337
338 nlh = (struct nlmsghdr *)skb->data;
339 nlh->nlmsg_pid = 0; /* from kernel */
340 nlh->nlmsg_flags = 0;
341 nlh->nlmsg_seq = 0;
342 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
343 aniHdr = NLMSG_DATA(nlh);
344 aniHdr->type = ANI_MSG_OEM_DATA_RSP;
345
346 aniHdr->length = length;
347 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
348 oemData = (uint8_t *) ((char *)aniHdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530349 qdf_mem_copy(oemData, oemDataRsp, length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800350
351 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
352
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530353 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800354 "%s: sending Oem Data Response of len (%d) to process pid (%d)",
355 __func__, length, p_hdd_ctx->oem_pid);
356
357 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
358
359 return;
360}
361
362/**
363 * oem_process_data_req_msg() - process oem data request
364 * @oemDataLen: Length to OEM Data buffer
365 * @oemData: Pointer to OEM Data buffer
366 *
367 * This function sends oem message to SME
368 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530369 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530371static QDF_STATUS oem_process_data_req_msg(int oemDataLen, char *oemData)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800372{
373 hdd_adapter_t *pAdapter = NULL;
374 tOemDataReqConfig oemDataReqConfig;
375 uint32_t oemDataReqID = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530376 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800377
378 /* for now, STA interface only */
Krunal Sonibe766b02016-03-10 13:00:44 -0800379 pAdapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800380 if (!pAdapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530381 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800382 "%s: No adapter for STA mode", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530383 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800384 }
385
386 if (!oemData) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530387 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388 "%s: oemData is null", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530389 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800390 }
391
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530392 qdf_mem_zero(&oemDataReqConfig, sizeof(tOemDataReqConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800393
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530394 oemDataReqConfig.data = qdf_mem_malloc(oemDataLen);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800395 if (!oemDataReqConfig.data) {
396 hddLog(LOGE, FL("malloc failed for data req buffer"));
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530397 return QDF_STATUS_E_NOMEM;
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800398 }
399
400 oemDataReqConfig.data_len = oemDataLen;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530401 qdf_mem_copy(oemDataReqConfig.data, oemData, oemDataLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800402
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530403 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800404 "%s: calling sme_oem_data_req", __func__);
405
406 status = sme_oem_data_req(p_hdd_ctx->hHal,
407 pAdapter->sessionId,
408 &oemDataReqConfig,
Jeff Johnsonf6358f12015-12-07 13:36:10 -0800409 &oemDataReqID);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800410
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530411 qdf_mem_free(oemDataReqConfig.data);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800412 oemDataReqConfig.data = NULL;
413
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800414 return status;
415}
416
417/**
418 * oem_process_channel_info_req_msg() - process oem channel_info request
419 * @numOfChannels: number of channels
420 * @chanList: list of channel information
421 *
422 * This function responds with channel info to oem process
423 *
424 * Return: 0 for success, non zero for failure
425 */
426static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList)
427{
428 struct sk_buff *skb;
429 struct nlmsghdr *nlh;
430 tAniMsgHdr *aniHdr;
431 tHddChannelInfo *pHddChanInfo;
432 tHddChannelInfo hddChanInfo;
433 uint8_t chanId;
434 uint32_t reg_info_1;
435 uint32_t reg_info_2;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530436 QDF_STATUS status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800437 int i;
438 uint8_t *buf;
439
440 /* OEM message is always to a specific process and cannot be a broadcast */
441 if (p_hdd_ctx->oem_pid == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530442 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800443 "%s: invalid dest pid", __func__);
444 return -EPERM;
445 }
446
447 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) +
448 numOfChannels * sizeof(tHddChannelInfo)),
449 GFP_KERNEL);
450 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530451 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800452 "%s: alloc_skb failed", __func__);
453 return -ENOMEM;
454 }
455
456 nlh = (struct nlmsghdr *)skb->data;
457 nlh->nlmsg_pid = 0; /* from kernel */
458 nlh->nlmsg_flags = 0;
459 nlh->nlmsg_seq = 0;
460 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
461 aniHdr = NLMSG_DATA(nlh);
462 aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP;
463
464 aniHdr->length =
465 sizeof(uint8_t) + numOfChannels * sizeof(tHddChannelInfo);
466 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
467
468 /* First byte of message body will have num of channels */
469 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
470 *buf++ = numOfChannels;
471
472 /* Next follows channel info struct for each channel id.
473 * If chan id is wrong or SME returns failure for a channel
474 * then fill in 0 in channel info for that particular channel
475 */
476 for (i = 0; i < numOfChannels; i++) {
477 pHddChanInfo = (tHddChannelInfo *) ((char *)buf +
478 i *
479 sizeof(tHddChannelInfo));
480
481 chanId = chanList[i];
482 status = sme_get_reg_info(p_hdd_ctx->hHal, chanId,
483 &reg_info_1, &reg_info_2);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530484 if (QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800485 /* copy into hdd chan info struct */
486 hddChanInfo.chan_id = chanId;
487 hddChanInfo.reserved0 = 0;
488 hddChanInfo.mhz = cds_chan_to_freq(chanId);
489 hddChanInfo.band_center_freq1 = hddChanInfo.mhz;
490 hddChanInfo.band_center_freq2 = 0;
491
492 hddChanInfo.info = 0;
493 if (CHANNEL_STATE_DFS ==
494 cds_get_channel_state(chanId))
495 WMI_SET_CHANNEL_FLAG(&hddChanInfo,
496 WMI_CHAN_FLAG_DFS);
497 hddChanInfo.reg_info_1 = reg_info_1;
498 hddChanInfo.reg_info_2 = reg_info_2;
499 } else {
500 /* channel info is not returned, fill in zeros in channel
501 * info struct
502 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530503 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800504 "%s: sme_get_reg_info failed for chan (%d), return info 0",
505 __func__, chanId);
506 hddChanInfo.chan_id = chanId;
507 hddChanInfo.reserved0 = 0;
508 hddChanInfo.mhz = 0;
509 hddChanInfo.band_center_freq1 = 0;
510 hddChanInfo.band_center_freq2 = 0;
511 hddChanInfo.info = 0;
512 hddChanInfo.reg_info_1 = 0;
513 hddChanInfo.reg_info_2 = 0;
514 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530515 qdf_mem_copy(pHddChanInfo, &hddChanInfo,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800516 sizeof(tHddChannelInfo));
517 }
518
519 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
520
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530521 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800522 "%s: sending channel info resp for num channels (%d) to pid (%d)",
523 __func__, numOfChannels, p_hdd_ctx->oem_pid);
524
525 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
526
527 return 0;
528}
529
530/**
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800531 * oem_process_set_cap_req_msg() - process oem set capability request
532 * @oem_cap_len: Length of OEM capability
533 * @oem_cap: Pointer to OEM capability buffer
534 * @app_pid: process ID, to which rsp message is to be sent
535 *
536 * This function sends oem message to SME
537 *
538 * Return: error code
539 */
540static int oem_process_set_cap_req_msg(int oem_cap_len,
541 char *oem_cap, int32_t app_pid)
542{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530543 QDF_STATUS status;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800544 int error_code;
545 struct sk_buff *skb;
546 struct nlmsghdr *nlh;
547 tAniMsgHdr *ani_hdr;
548 uint8_t *buf;
549
550 if (!oem_cap) {
551 hdd_err("oem_cap is null");
552 return -EINVAL;
553 }
554
555 status = sme_oem_update_capability(p_hdd_ctx->hHal,
556 (struct sme_oem_capability *)oem_cap);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530557 if (!QDF_IS_STATUS_SUCCESS(status))
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800558 hdd_err("error updating rm capability, status: %d", status);
Anurag Chouhanc5548422016-02-24 18:33:27 +0530559 error_code = qdf_status_to_os_return(status);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800560
561 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
562 if (skb == NULL) {
563 hdd_err("alloc_skb failed");
564 return -ENOMEM;
565 }
566
567 nlh = (struct nlmsghdr *)skb->data;
568 nlh->nlmsg_pid = 0; /* from kernel */
569 nlh->nlmsg_flags = 0;
570 nlh->nlmsg_seq = 0;
571 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
572 ani_hdr = NLMSG_DATA(nlh);
573 ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP;
574 /* 64 bit alignment */
575 ani_hdr->length = sizeof(error_code);
576 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length);
577
578 /* message body will contain only status code */
579 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530580 qdf_mem_copy(buf, &error_code, ani_hdr->length);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800581
582 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length));
583
584 hdd_info("sending oem response to process pid %d", app_pid);
585
586 (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
587
588 return error_code;
589}
590
591/**
592 * oem_process_get_cap_req_msg() - process oem get capability request
593 *
594 * This function process the get capability request from OEM and responds
595 * with the capability.
596 *
597 * Return: error code
598 */
599static int oem_process_get_cap_req_msg(void)
600{
601 int error_code;
602 struct oem_get_capability_rsp *cap_rsp;
603 t_iw_oem_data_cap data_cap = { {0} };
604 struct sme_oem_capability oem_cap;
605 hdd_adapter_t *adapter;
606 struct sk_buff *skb;
607 struct nlmsghdr *nlh;
608 tAniMsgHdr *ani_hdr;
609 uint8_t *buf;
610
611 /* for now, STA interface only */
Krunal Sonibe766b02016-03-10 13:00:44 -0800612 adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800613 if (!adapter) {
614 hdd_err("No adapter for STA mode");
615 return -EINVAL;
616 }
617
618 error_code = populate_oem_data_cap(adapter, &data_cap);
619 if (0 != error_code)
620 return error_code;
621
622 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)),
623 GFP_KERNEL);
624 if (skb == NULL) {
625 hdd_err("alloc_skb failed");
626 return -ENOMEM;
627 }
628
629 nlh = (struct nlmsghdr *)skb->data;
630 nlh->nlmsg_pid = 0; /* from kernel */
631 nlh->nlmsg_flags = 0;
632 nlh->nlmsg_seq = 0;
633 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
634 ani_hdr = NLMSG_DATA(nlh);
635 ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP;
636
637 ani_hdr->length = sizeof(*cap_rsp);
638 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
639
640 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530641 qdf_mem_copy(buf, &data_cap, sizeof(data_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800642
643 buf = (char *) buf + sizeof(data_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530644 qdf_mem_zero(&oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800645 sme_oem_get_capability(p_hdd_ctx->hHal, &oem_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530646 qdf_mem_copy(buf, &oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800647
648 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
649 hdd_info("send rsp to oem-pid:%d for get_capability",
650 p_hdd_ctx->oem_pid);
651
652 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
653 return 0;
654}
655
656/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800657 * hdd_send_peer_status_ind_to_oem_app() -
658 * Function to send peer status to a registered application
659 * @peerMac: MAC address of peer
660 * @peerStatus: ePeerConnected or ePeerDisconnected
661 * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0
662 * @sessionId: SME session id, i.e. vdev_id
663 * @chan_info: operating channel information
664 *
665 * Return: none
666 */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530667void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800668 uint8_t peerStatus,
669 uint8_t peerTimingMeasCap,
670 uint8_t sessionId,
671 tSirSmeChanInfo *chan_info)
672{
673 struct sk_buff *skb;
674 struct nlmsghdr *nlh;
675 tAniMsgHdr *aniHdr;
676 tPeerStatusInfo *pPeerInfo;
677
678 if (!p_hdd_ctx || !p_hdd_ctx->hHal) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530679 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800680 "%s: Either HDD Ctx is null or Hal Ctx is null",
681 __func__);
682 return;
683 }
684
685 /* check if oem app has registered and pid is valid */
686 if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530687 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800688 "%s: OEM app is not registered(%d) or pid is invalid(%d)",
689 __func__, p_hdd_ctx->oem_app_registered,
690 p_hdd_ctx->oem_pid);
691 return;
692 }
693
694 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) +
695 sizeof(tPeerStatusInfo)),
696 GFP_KERNEL);
697 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530698 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800699 "%s: alloc_skb failed", __func__);
700 return;
701 }
702
703 nlh = (struct nlmsghdr *)skb->data;
704 nlh->nlmsg_pid = 0; /* from kernel */
705 nlh->nlmsg_flags = 0;
706 nlh->nlmsg_seq = 0;
707 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
708 aniHdr = NLMSG_DATA(nlh);
709 aniHdr->type = ANI_MSG_PEER_STATUS_IND;
710
711 aniHdr->length = sizeof(tPeerStatusInfo);
712 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
713
714 pPeerInfo = (tPeerStatusInfo *) ((char *)aniHdr + sizeof(tAniMsgHdr));
715
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530716 qdf_mem_copy(pPeerInfo->peer_mac_addr, peerMac->bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800717 sizeof(peerMac->bytes));
718 pPeerInfo->peer_status = peerStatus;
719 pPeerInfo->vdev_id = sessionId;
720 pPeerInfo->peer_capability = peerTimingMeasCap;
721 pPeerInfo->reserved0 = 0;
722
723 if (chan_info) {
724 pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id;
725 pPeerInfo->peer_chan_info.reserved0 = 0;
726 pPeerInfo->peer_chan_info.mhz = chan_info->mhz;
727 pPeerInfo->peer_chan_info.band_center_freq1 =
728 chan_info->band_center_freq1;
729 pPeerInfo->peer_chan_info.band_center_freq2 =
730 chan_info->band_center_freq2;
731 pPeerInfo->peer_chan_info.info = chan_info->info;
732 pPeerInfo->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
733 pPeerInfo->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
734 } else {
735 pPeerInfo->peer_chan_info.chan_id = 0;
736 pPeerInfo->peer_chan_info.reserved0 = 0;
737 pPeerInfo->peer_chan_info.mhz = 0;
738 pPeerInfo->peer_chan_info.band_center_freq1 = 0;
739 pPeerInfo->peer_chan_info.band_center_freq2 = 0;
740 pPeerInfo->peer_chan_info.info = 0;
741 pPeerInfo->peer_chan_info.reg_info_1 = 0;
742 pPeerInfo->peer_chan_info.reg_info_2 = 0;
743 }
744 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
745
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530746 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800747 "%s: sending peer " MAC_ADDRESS_STR
748 " status(%d), peerTimingMeasCap(%d), vdevId(%d), chanId(%d)"
749 " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d),"
750 " info (0x%x), frequency (%d),reg info 1 (0x%x),"
751 " reg info 2 (0x%x)", __func__,
752 MAC_ADDR_ARRAY(peerMac->bytes),
753 peerStatus, peerTimingMeasCap,
754 sessionId, pPeerInfo->peer_chan_info.chan_id,
755 p_hdd_ctx->oem_pid,
756 pPeerInfo->peer_chan_info.band_center_freq1,
757 pPeerInfo->peer_chan_info.band_center_freq2,
758 pPeerInfo->peer_chan_info.info,
759 pPeerInfo->peer_chan_info.mhz,
760 pPeerInfo->peer_chan_info.reg_info_1,
761 pPeerInfo->peer_chan_info.reg_info_2);
762
763 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
764
765 return;
766}
767
768/*
769 * Callback function invoked by Netlink service for all netlink
770 * messages (from user space) addressed to WLAN_NL_MSG_OEM
771 */
772
773/**
774 * oem_msg_callback() - callback invoked by netlink service
775 * @skb: skb with netlink message
776 *
777 * This function gets invoked by netlink service when a message
778 * is received from user space addressed to WLAN_NL_MSG_OEM
779 *
780 * Return: zero on success
781 * On error, error number will be returned.
782 */
783static int oem_msg_callback(struct sk_buff *skb)
784{
785 struct nlmsghdr *nlh;
786 tAniMsgHdr *msg_hdr;
787 int ret;
788 char *sign_str = NULL;
789 nlh = (struct nlmsghdr *)skb->data;
790
791 if (!nlh) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530792 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800793 "%s: Netlink header null", __func__);
794 return -EPERM;
795 }
796
797 ret = wlan_hdd_validate_context(p_hdd_ctx);
798 if (0 != ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530799 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800800 FL("HDD context is not valid"));
801 return ret;
802 }
803
804 msg_hdr = NLMSG_DATA(nlh);
805
806 if (!msg_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530807 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800808 "%s: Message header null", __func__);
809 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
810 OEM_ERR_NULL_MESSAGE_HEADER);
811 return -EPERM;
812 }
813
814 if (nlh->nlmsg_len <
815 NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530816 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800817 "%s: Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)",
818 __func__, nlh->nlmsg_len, msg_hdr->length);
819 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
820 OEM_ERR_INVALID_MESSAGE_LENGTH);
821 return -EPERM;
822 }
823
824 switch (msg_hdr->type) {
825 case ANI_MSG_APP_REG_REQ:
826 /* Registration request is only allowed for Qualcomm Application */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530827 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800828 "%s: Received App Req Req from App process pid(%d), len(%d)",
829 __func__, nlh->nlmsg_pid, msg_hdr->length);
830
831 sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr));
832 if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) &&
833 (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR,
834 OEM_APP_SIGNATURE_LEN))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530835 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800836 "%s: Valid App Req Req from oem app process pid(%d)",
837 __func__, nlh->nlmsg_pid);
838
839 p_hdd_ctx->oem_app_registered = true;
840 p_hdd_ctx->oem_pid = nlh->nlmsg_pid;
841 send_oem_reg_rsp_nlink_msg();
842 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530843 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844 "%s: Invalid signature in App Reg Request from pid(%d)",
845 __func__, nlh->nlmsg_pid);
846 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
847 OEM_ERR_INVALID_SIGNATURE);
848 return -EPERM;
849 }
850 break;
851
852 case ANI_MSG_OEM_DATA_REQ:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530853 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854 "%s: Received Oem Data Request length(%d) from pid: %d",
855 __func__, msg_hdr->length, nlh->nlmsg_pid);
856
857 if ((!p_hdd_ctx->oem_app_registered) ||
858 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
859 /* either oem app is not registered yet or pid is different */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530860 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800861 "%s: OEM DataReq: app not registered(%d) or incorrect pid(%d)",
862 __func__, p_hdd_ctx->oem_app_registered,
863 nlh->nlmsg_pid);
864 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
865 OEM_ERR_APP_NOT_REGISTERED);
866 return -EPERM;
867 }
868
869 if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530870 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800871 "%s: Invalid length (%d) in Oem Data Request",
872 __func__, msg_hdr->length);
873 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
874 OEM_ERR_INVALID_MESSAGE_LENGTH);
875 return -EPERM;
876 }
877 oem_process_data_req_msg(msg_hdr->length,
878 (char *)((char *)msg_hdr +
879 sizeof(tAniMsgHdr)));
880 break;
881
882 case ANI_MSG_CHANNEL_INFO_REQ:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530883 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800884 "%s: Received channel info request, num channel(%d) from pid: %d",
885 __func__, msg_hdr->length, nlh->nlmsg_pid);
886
887 if ((!p_hdd_ctx->oem_app_registered) ||
888 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
889 /* either oem app is not registered yet or pid is different */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530890 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800891 "%s: Chan InfoReq: app not registered(%d) or incorrect pid(%d)",
892 __func__, p_hdd_ctx->oem_app_registered,
893 nlh->nlmsg_pid);
894 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
895 OEM_ERR_APP_NOT_REGISTERED);
896 return -EPERM;
897 }
898
899 /* message length contains list of channel ids */
900 if ((!msg_hdr->length) ||
901 (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530902 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800903 "%s: Invalid length (%d) in channel info request",
904 __func__, msg_hdr->length);
905 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
906 OEM_ERR_INVALID_MESSAGE_LENGTH);
907 return -EPERM;
908 }
909 oem_process_channel_info_req_msg(msg_hdr->length,
910 (char *)((char *)msg_hdr +
911 sizeof(tAniMsgHdr)));
912 break;
913
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800914 case ANI_MSG_SET_OEM_CAP_REQ:
915 hdd_info("Received set oem capability req of length:%d from pid: %d",
916 msg_hdr->length, nlh->nlmsg_pid);
917
918 if ((!p_hdd_ctx->oem_app_registered) ||
919 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
920 /* oem app is not registered yet or pid is different */
921 hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)",
922 p_hdd_ctx->oem_app_registered,
923 nlh->nlmsg_pid);
924 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
925 OEM_ERR_APP_NOT_REGISTERED);
926 return -EPERM;
927 }
928
929 if ((!msg_hdr->length) ||
930 (sizeof(struct sme_oem_capability) < msg_hdr->length)) {
931 hdd_err("Invalid length (%d) in set_oem_capability",
932 msg_hdr->length);
933 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
934 OEM_ERR_INVALID_MESSAGE_LENGTH);
935 return -EPERM;
936 }
937
938 oem_process_set_cap_req_msg(msg_hdr->length,
939 (char *)((char *)msg_hdr +
940 sizeof(tAniMsgHdr)),
941 nlh->nlmsg_pid);
942 break;
943
944 case ANI_MSG_GET_OEM_CAP_REQ:
945 hdd_info("Rcvd get oem capability req of length:%d from pid: %d",
946 msg_hdr->length, nlh->nlmsg_pid);
947
948 if ((!p_hdd_ctx->oem_app_registered) ||
949 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
950 /* oem app is not registered yet or pid is different */
951 hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)",
952 p_hdd_ctx->oem_app_registered,
953 nlh->nlmsg_pid);
954 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
955 OEM_ERR_APP_NOT_REGISTERED);
956 return -EPERM;
957 }
958
959 oem_process_get_cap_req_msg();
960 break;
961
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530963 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800964 "%s: Received Invalid message type (%d), length (%d)",
965 __func__, msg_hdr->type, msg_hdr->length);
966 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
967 OEM_ERR_INVALID_MESSAGE_TYPE);
968 return -EPERM;
969 }
970 return 0;
971}
972
973static int __oem_msg_callback(struct sk_buff *skb)
974{
975 int ret;
976
977 cds_ssr_protect(__func__);
978 ret = oem_msg_callback(skb);
979 cds_ssr_unprotect(__func__);
980
981 return ret;
982}
983
984/**
985 * oem_activate_service() - Activate oem message handler
986 * @hdd_ctx: pointer to global HDD context
987 *
988 * This function registers a handler to receive netlink message from
989 * an OEM application process.
990 *
991 * Return: zero on success
992 * On error, error number will be returned.
993 */
994int oem_activate_service(struct hdd_context_s *hdd_ctx)
995{
996 p_hdd_ctx = hdd_ctx;
997
998 /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
999 return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback);
1000}
1001
1002#endif