blob: 924ac2eb2fa7efc817b7251f46dbbfd3ccef2d28 [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);
153 if (!status)
154 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800155
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800156 pHddOemDataCap = (t_iw_oem_data_cap *) (extra);
157 *pHddOemDataCap = oemDataCap;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800158
159 EXIT();
160 return 0;
161}
162
163/**
164 * send_oem_reg_rsp_nlink_msg() - send oem registration response
165 *
166 * This function sends oem message to registered application process
167 *
168 * Return: none
169 */
170static void send_oem_reg_rsp_nlink_msg(void)
171{
172 struct sk_buff *skb;
173 struct nlmsghdr *nlh;
174 tAniMsgHdr *aniHdr;
175 uint8_t *buf;
176 uint8_t *numInterfaces;
177 uint8_t *deviceMode;
178 uint8_t *vdevId;
179 hdd_adapter_list_node_t *pAdapterNode = NULL;
180 hdd_adapter_list_node_t *pNext = NULL;
181 hdd_adapter_t *pAdapter = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530182 QDF_STATUS status = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800183
184 /* OEM message is always to a specific process and cannot be a broadcast */
185 if (p_hdd_ctx->oem_pid == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530186 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800187 "%s: invalid dest pid", __func__);
188 return;
189 }
190
191 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
192 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530193 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800194 "%s: alloc_skb failed", __func__);
195 return;
196 }
197
198 nlh = (struct nlmsghdr *)skb->data;
199 nlh->nlmsg_pid = 0; /* from kernel */
200 nlh->nlmsg_flags = 0;
201 nlh->nlmsg_seq = 0;
202 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
203 aniHdr = NLMSG_DATA(nlh);
204 aniHdr->type = ANI_MSG_APP_REG_RSP;
205
206 /* Fill message body:
207 * First byte will be number of interfaces, followed by
208 * two bytes for each interfaces
209 * - one byte for device mode
210 * - one byte for vdev id
211 */
212 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
213 numInterfaces = buf++;
214 *numInterfaces = 0;
215
216 /* Iterate through each of the adapters and fill device mode and vdev id */
217 status = hdd_get_front_adapter(p_hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530218 while ((QDF_STATUS_SUCCESS == status) && pAdapterNode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800219 pAdapter = pAdapterNode->pAdapter;
220 if (pAdapter) {
221 deviceMode = buf++;
222 vdevId = buf++;
223 *deviceMode = pAdapter->device_mode;
224 *vdevId = pAdapter->sessionId;
225 (*numInterfaces)++;
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530226 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800227 "%s: numInterfaces: %d, deviceMode: %d, vdevId: %d",
228 __func__, *numInterfaces, *deviceMode,
229 *vdevId);
230 }
231 status = hdd_get_next_adapter(p_hdd_ctx, pAdapterNode, &pNext);
232 pAdapterNode = pNext;
233 }
234
235 aniHdr->length =
236 sizeof(uint8_t) + (*numInterfaces) * 2 * sizeof(uint8_t);
237 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
238
239 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
240
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530241 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800242 "%s: sending App Reg Response length (%d) to process pid (%d)",
243 __func__, aniHdr->length, p_hdd_ctx->oem_pid);
244
245 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
246
247 return;
248}
249
250/**
251 * send_oem_err_rsp_nlink_msg() - send oem error response
252 * @app_pid: PID of oem application process
253 * @error_code: response error code
254 *
255 * This function sends error response to oem app
256 *
257 * Return: none
258 */
259static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code)
260{
261 struct sk_buff *skb;
262 struct nlmsghdr *nlh;
263 tAniMsgHdr *aniHdr;
264 uint8_t *buf;
265
266 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
267 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530268 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800269 "%s: alloc_skb failed", __func__);
270 return;
271 }
272
273 nlh = (struct nlmsghdr *)skb->data;
274 nlh->nlmsg_pid = 0; /* from kernel */
275 nlh->nlmsg_flags = 0;
276 nlh->nlmsg_seq = 0;
277 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
278 aniHdr = NLMSG_DATA(nlh);
279 aniHdr->type = ANI_MSG_OEM_ERROR;
280 aniHdr->length = sizeof(uint8_t);
281 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + aniHdr->length);
282
283 /* message body will contain one byte of error code */
284 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
285 *buf = error_code;
286
287 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + aniHdr->length));
288
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530289 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800290 "%s: sending oem error response to process pid (%d)",
291 __func__, app_pid);
292
293 (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
294
295 return;
296}
297
298/**
299 * hdd_send_oem_data_rsp_msg() - send oem data response
300 * @length: length of the OEM Data Response message
301 * @oemDataRsp: the actual OEM Data Response message
302 *
303 * This function sends an OEM Data Response message to a registered
304 * application process over the netlink socket.
305 *
306 * Return: 0 for success, non zero for failure
307 */
308void hdd_send_oem_data_rsp_msg(int length, uint8_t *oemDataRsp)
309{
310 struct sk_buff *skb;
311 struct nlmsghdr *nlh;
312 tAniMsgHdr *aniHdr;
313 uint8_t *oemData;
314
315 /* OEM message is always to a specific process and cannot be a broadcast */
316 if (p_hdd_ctx->oem_pid == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530317 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800318 "%s: invalid dest pid", __func__);
319 return;
320 }
321
322 if (length > OEM_DATA_RSP_SIZE) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530323 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800324 "%s: invalid length of Oem Data response", __func__);
325 return;
326 }
327
328 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + OEM_DATA_RSP_SIZE),
329 GFP_KERNEL);
330 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530331 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800332 "%s: alloc_skb failed", __func__);
333 return;
334 }
335
336 nlh = (struct nlmsghdr *)skb->data;
337 nlh->nlmsg_pid = 0; /* from kernel */
338 nlh->nlmsg_flags = 0;
339 nlh->nlmsg_seq = 0;
340 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
341 aniHdr = NLMSG_DATA(nlh);
342 aniHdr->type = ANI_MSG_OEM_DATA_RSP;
343
344 aniHdr->length = length;
345 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
346 oemData = (uint8_t *) ((char *)aniHdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530347 qdf_mem_copy(oemData, oemDataRsp, length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800348
349 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
350
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530351 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800352 "%s: sending Oem Data Response of len (%d) to process pid (%d)",
353 __func__, length, p_hdd_ctx->oem_pid);
354
355 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
356
357 return;
358}
359
360/**
361 * oem_process_data_req_msg() - process oem data request
362 * @oemDataLen: Length to OEM Data buffer
363 * @oemData: Pointer to OEM Data buffer
364 *
365 * This function sends oem message to SME
366 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530367 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800368 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530369static QDF_STATUS oem_process_data_req_msg(int oemDataLen, char *oemData)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800370{
371 hdd_adapter_t *pAdapter = NULL;
372 tOemDataReqConfig oemDataReqConfig;
373 uint32_t oemDataReqID = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530374 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800375
376 /* for now, STA interface only */
377 pAdapter = hdd_get_adapter(p_hdd_ctx, WLAN_HDD_INFRA_STATION);
378 if (!pAdapter) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530379 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800380 "%s: No adapter for STA mode", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530381 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800382 }
383
384 if (!oemData) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530385 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800386 "%s: oemData is null", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530387 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800388 }
389
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530390 qdf_mem_zero(&oemDataReqConfig, sizeof(tOemDataReqConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800391
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530392 oemDataReqConfig.data = qdf_mem_malloc(oemDataLen);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800393 if (!oemDataReqConfig.data) {
394 hddLog(LOGE, FL("malloc failed for data req buffer"));
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530395 return QDF_STATUS_E_NOMEM;
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800396 }
397
398 oemDataReqConfig.data_len = oemDataLen;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530399 qdf_mem_copy(oemDataReqConfig.data, oemData, oemDataLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800400
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530401 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800402 "%s: calling sme_oem_data_req", __func__);
403
404 status = sme_oem_data_req(p_hdd_ctx->hHal,
405 pAdapter->sessionId,
406 &oemDataReqConfig,
Jeff Johnsonf6358f12015-12-07 13:36:10 -0800407 &oemDataReqID);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800408
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530409 qdf_mem_free(oemDataReqConfig.data);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800410 oemDataReqConfig.data = NULL;
411
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800412 return status;
413}
414
415/**
416 * oem_process_channel_info_req_msg() - process oem channel_info request
417 * @numOfChannels: number of channels
418 * @chanList: list of channel information
419 *
420 * This function responds with channel info to oem process
421 *
422 * Return: 0 for success, non zero for failure
423 */
424static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList)
425{
426 struct sk_buff *skb;
427 struct nlmsghdr *nlh;
428 tAniMsgHdr *aniHdr;
429 tHddChannelInfo *pHddChanInfo;
430 tHddChannelInfo hddChanInfo;
431 uint8_t chanId;
432 uint32_t reg_info_1;
433 uint32_t reg_info_2;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530434 QDF_STATUS status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800435 int i;
436 uint8_t *buf;
437
438 /* OEM message is always to a specific process and cannot be a broadcast */
439 if (p_hdd_ctx->oem_pid == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530440 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800441 "%s: invalid dest pid", __func__);
442 return -EPERM;
443 }
444
445 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) +
446 numOfChannels * sizeof(tHddChannelInfo)),
447 GFP_KERNEL);
448 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530449 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800450 "%s: alloc_skb failed", __func__);
451 return -ENOMEM;
452 }
453
454 nlh = (struct nlmsghdr *)skb->data;
455 nlh->nlmsg_pid = 0; /* from kernel */
456 nlh->nlmsg_flags = 0;
457 nlh->nlmsg_seq = 0;
458 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
459 aniHdr = NLMSG_DATA(nlh);
460 aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP;
461
462 aniHdr->length =
463 sizeof(uint8_t) + numOfChannels * sizeof(tHddChannelInfo);
464 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
465
466 /* First byte of message body will have num of channels */
467 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
468 *buf++ = numOfChannels;
469
470 /* Next follows channel info struct for each channel id.
471 * If chan id is wrong or SME returns failure for a channel
472 * then fill in 0 in channel info for that particular channel
473 */
474 for (i = 0; i < numOfChannels; i++) {
475 pHddChanInfo = (tHddChannelInfo *) ((char *)buf +
476 i *
477 sizeof(tHddChannelInfo));
478
479 chanId = chanList[i];
480 status = sme_get_reg_info(p_hdd_ctx->hHal, chanId,
481 &reg_info_1, &reg_info_2);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530482 if (QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800483 /* copy into hdd chan info struct */
484 hddChanInfo.chan_id = chanId;
485 hddChanInfo.reserved0 = 0;
486 hddChanInfo.mhz = cds_chan_to_freq(chanId);
487 hddChanInfo.band_center_freq1 = hddChanInfo.mhz;
488 hddChanInfo.band_center_freq2 = 0;
489
490 hddChanInfo.info = 0;
491 if (CHANNEL_STATE_DFS ==
492 cds_get_channel_state(chanId))
493 WMI_SET_CHANNEL_FLAG(&hddChanInfo,
494 WMI_CHAN_FLAG_DFS);
495 hddChanInfo.reg_info_1 = reg_info_1;
496 hddChanInfo.reg_info_2 = reg_info_2;
497 } else {
498 /* channel info is not returned, fill in zeros in channel
499 * info struct
500 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530501 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800502 "%s: sme_get_reg_info failed for chan (%d), return info 0",
503 __func__, chanId);
504 hddChanInfo.chan_id = chanId;
505 hddChanInfo.reserved0 = 0;
506 hddChanInfo.mhz = 0;
507 hddChanInfo.band_center_freq1 = 0;
508 hddChanInfo.band_center_freq2 = 0;
509 hddChanInfo.info = 0;
510 hddChanInfo.reg_info_1 = 0;
511 hddChanInfo.reg_info_2 = 0;
512 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530513 qdf_mem_copy(pHddChanInfo, &hddChanInfo,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800514 sizeof(tHddChannelInfo));
515 }
516
517 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
518
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530519 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800520 "%s: sending channel info resp for num channels (%d) to pid (%d)",
521 __func__, numOfChannels, p_hdd_ctx->oem_pid);
522
523 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
524
525 return 0;
526}
527
528/**
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800529 * oem_process_set_cap_req_msg() - process oem set capability request
530 * @oem_cap_len: Length of OEM capability
531 * @oem_cap: Pointer to OEM capability buffer
532 * @app_pid: process ID, to which rsp message is to be sent
533 *
534 * This function sends oem message to SME
535 *
536 * Return: error code
537 */
538static int oem_process_set_cap_req_msg(int oem_cap_len,
539 char *oem_cap, int32_t app_pid)
540{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530541 QDF_STATUS status;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800542 int error_code;
543 struct sk_buff *skb;
544 struct nlmsghdr *nlh;
545 tAniMsgHdr *ani_hdr;
546 uint8_t *buf;
547
548 if (!oem_cap) {
549 hdd_err("oem_cap is null");
550 return -EINVAL;
551 }
552
553 status = sme_oem_update_capability(p_hdd_ctx->hHal,
554 (struct sme_oem_capability *)oem_cap);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530555 if (!QDF_IS_STATUS_SUCCESS(status))
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800556 hdd_err("error updating rm capability, status: %d", status);
Anurag Chouhanc5548422016-02-24 18:33:27 +0530557 error_code = qdf_status_to_os_return(status);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800558
559 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
560 if (skb == NULL) {
561 hdd_err("alloc_skb failed");
562 return -ENOMEM;
563 }
564
565 nlh = (struct nlmsghdr *)skb->data;
566 nlh->nlmsg_pid = 0; /* from kernel */
567 nlh->nlmsg_flags = 0;
568 nlh->nlmsg_seq = 0;
569 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
570 ani_hdr = NLMSG_DATA(nlh);
571 ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP;
572 /* 64 bit alignment */
573 ani_hdr->length = sizeof(error_code);
574 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length);
575
576 /* message body will contain only status code */
577 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530578 qdf_mem_copy(buf, &error_code, ani_hdr->length);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800579
580 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length));
581
582 hdd_info("sending oem response to process pid %d", app_pid);
583
584 (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
585
586 return error_code;
587}
588
589/**
590 * oem_process_get_cap_req_msg() - process oem get capability request
591 *
592 * This function process the get capability request from OEM and responds
593 * with the capability.
594 *
595 * Return: error code
596 */
597static int oem_process_get_cap_req_msg(void)
598{
599 int error_code;
600 struct oem_get_capability_rsp *cap_rsp;
601 t_iw_oem_data_cap data_cap = { {0} };
602 struct sme_oem_capability oem_cap;
603 hdd_adapter_t *adapter;
604 struct sk_buff *skb;
605 struct nlmsghdr *nlh;
606 tAniMsgHdr *ani_hdr;
607 uint8_t *buf;
608
609 /* for now, STA interface only */
610 adapter = hdd_get_adapter(p_hdd_ctx, WLAN_HDD_INFRA_STATION);
611 if (!adapter) {
612 hdd_err("No adapter for STA mode");
613 return -EINVAL;
614 }
615
616 error_code = populate_oem_data_cap(adapter, &data_cap);
617 if (0 != error_code)
618 return error_code;
619
620 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)),
621 GFP_KERNEL);
622 if (skb == NULL) {
623 hdd_err("alloc_skb failed");
624 return -ENOMEM;
625 }
626
627 nlh = (struct nlmsghdr *)skb->data;
628 nlh->nlmsg_pid = 0; /* from kernel */
629 nlh->nlmsg_flags = 0;
630 nlh->nlmsg_seq = 0;
631 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
632 ani_hdr = NLMSG_DATA(nlh);
633 ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP;
634
635 ani_hdr->length = sizeof(*cap_rsp);
636 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
637
638 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530639 qdf_mem_copy(buf, &data_cap, sizeof(data_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800640
641 buf = (char *) buf + sizeof(data_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530642 qdf_mem_zero(&oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800643 sme_oem_get_capability(p_hdd_ctx->hHal, &oem_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530644 qdf_mem_copy(buf, &oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800645
646 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
647 hdd_info("send rsp to oem-pid:%d for get_capability",
648 p_hdd_ctx->oem_pid);
649
650 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
651 return 0;
652}
653
654/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800655 * hdd_send_peer_status_ind_to_oem_app() -
656 * Function to send peer status to a registered application
657 * @peerMac: MAC address of peer
658 * @peerStatus: ePeerConnected or ePeerDisconnected
659 * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0
660 * @sessionId: SME session id, i.e. vdev_id
661 * @chan_info: operating channel information
662 *
663 * Return: none
664 */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530665void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800666 uint8_t peerStatus,
667 uint8_t peerTimingMeasCap,
668 uint8_t sessionId,
669 tSirSmeChanInfo *chan_info)
670{
671 struct sk_buff *skb;
672 struct nlmsghdr *nlh;
673 tAniMsgHdr *aniHdr;
674 tPeerStatusInfo *pPeerInfo;
675
676 if (!p_hdd_ctx || !p_hdd_ctx->hHal) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530677 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800678 "%s: Either HDD Ctx is null or Hal Ctx is null",
679 __func__);
680 return;
681 }
682
683 /* check if oem app has registered and pid is valid */
684 if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530685 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800686 "%s: OEM app is not registered(%d) or pid is invalid(%d)",
687 __func__, p_hdd_ctx->oem_app_registered,
688 p_hdd_ctx->oem_pid);
689 return;
690 }
691
692 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) +
693 sizeof(tPeerStatusInfo)),
694 GFP_KERNEL);
695 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530696 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800697 "%s: alloc_skb failed", __func__);
698 return;
699 }
700
701 nlh = (struct nlmsghdr *)skb->data;
702 nlh->nlmsg_pid = 0; /* from kernel */
703 nlh->nlmsg_flags = 0;
704 nlh->nlmsg_seq = 0;
705 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
706 aniHdr = NLMSG_DATA(nlh);
707 aniHdr->type = ANI_MSG_PEER_STATUS_IND;
708
709 aniHdr->length = sizeof(tPeerStatusInfo);
710 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
711
712 pPeerInfo = (tPeerStatusInfo *) ((char *)aniHdr + sizeof(tAniMsgHdr));
713
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530714 qdf_mem_copy(pPeerInfo->peer_mac_addr, peerMac->bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800715 sizeof(peerMac->bytes));
716 pPeerInfo->peer_status = peerStatus;
717 pPeerInfo->vdev_id = sessionId;
718 pPeerInfo->peer_capability = peerTimingMeasCap;
719 pPeerInfo->reserved0 = 0;
720
721 if (chan_info) {
722 pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id;
723 pPeerInfo->peer_chan_info.reserved0 = 0;
724 pPeerInfo->peer_chan_info.mhz = chan_info->mhz;
725 pPeerInfo->peer_chan_info.band_center_freq1 =
726 chan_info->band_center_freq1;
727 pPeerInfo->peer_chan_info.band_center_freq2 =
728 chan_info->band_center_freq2;
729 pPeerInfo->peer_chan_info.info = chan_info->info;
730 pPeerInfo->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
731 pPeerInfo->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
732 } else {
733 pPeerInfo->peer_chan_info.chan_id = 0;
734 pPeerInfo->peer_chan_info.reserved0 = 0;
735 pPeerInfo->peer_chan_info.mhz = 0;
736 pPeerInfo->peer_chan_info.band_center_freq1 = 0;
737 pPeerInfo->peer_chan_info.band_center_freq2 = 0;
738 pPeerInfo->peer_chan_info.info = 0;
739 pPeerInfo->peer_chan_info.reg_info_1 = 0;
740 pPeerInfo->peer_chan_info.reg_info_2 = 0;
741 }
742 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
743
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530744 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800745 "%s: sending peer " MAC_ADDRESS_STR
746 " status(%d), peerTimingMeasCap(%d), vdevId(%d), chanId(%d)"
747 " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d),"
748 " info (0x%x), frequency (%d),reg info 1 (0x%x),"
749 " reg info 2 (0x%x)", __func__,
750 MAC_ADDR_ARRAY(peerMac->bytes),
751 peerStatus, peerTimingMeasCap,
752 sessionId, pPeerInfo->peer_chan_info.chan_id,
753 p_hdd_ctx->oem_pid,
754 pPeerInfo->peer_chan_info.band_center_freq1,
755 pPeerInfo->peer_chan_info.band_center_freq2,
756 pPeerInfo->peer_chan_info.info,
757 pPeerInfo->peer_chan_info.mhz,
758 pPeerInfo->peer_chan_info.reg_info_1,
759 pPeerInfo->peer_chan_info.reg_info_2);
760
761 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
762
763 return;
764}
765
766/*
767 * Callback function invoked by Netlink service for all netlink
768 * messages (from user space) addressed to WLAN_NL_MSG_OEM
769 */
770
771/**
772 * oem_msg_callback() - callback invoked by netlink service
773 * @skb: skb with netlink message
774 *
775 * This function gets invoked by netlink service when a message
776 * is received from user space addressed to WLAN_NL_MSG_OEM
777 *
778 * Return: zero on success
779 * On error, error number will be returned.
780 */
781static int oem_msg_callback(struct sk_buff *skb)
782{
783 struct nlmsghdr *nlh;
784 tAniMsgHdr *msg_hdr;
785 int ret;
786 char *sign_str = NULL;
787 nlh = (struct nlmsghdr *)skb->data;
788
789 if (!nlh) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530790 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800791 "%s: Netlink header null", __func__);
792 return -EPERM;
793 }
794
795 ret = wlan_hdd_validate_context(p_hdd_ctx);
796 if (0 != ret) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530797 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800798 FL("HDD context is not valid"));
799 return ret;
800 }
801
802 msg_hdr = NLMSG_DATA(nlh);
803
804 if (!msg_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530805 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800806 "%s: Message header null", __func__);
807 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
808 OEM_ERR_NULL_MESSAGE_HEADER);
809 return -EPERM;
810 }
811
812 if (nlh->nlmsg_len <
813 NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530814 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800815 "%s: Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)",
816 __func__, nlh->nlmsg_len, msg_hdr->length);
817 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
818 OEM_ERR_INVALID_MESSAGE_LENGTH);
819 return -EPERM;
820 }
821
822 switch (msg_hdr->type) {
823 case ANI_MSG_APP_REG_REQ:
824 /* Registration request is only allowed for Qualcomm Application */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530825 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826 "%s: Received App Req Req from App process pid(%d), len(%d)",
827 __func__, nlh->nlmsg_pid, msg_hdr->length);
828
829 sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr));
830 if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) &&
831 (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR,
832 OEM_APP_SIGNATURE_LEN))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530833 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834 "%s: Valid App Req Req from oem app process pid(%d)",
835 __func__, nlh->nlmsg_pid);
836
837 p_hdd_ctx->oem_app_registered = true;
838 p_hdd_ctx->oem_pid = nlh->nlmsg_pid;
839 send_oem_reg_rsp_nlink_msg();
840 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530841 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800842 "%s: Invalid signature in App Reg Request from pid(%d)",
843 __func__, nlh->nlmsg_pid);
844 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
845 OEM_ERR_INVALID_SIGNATURE);
846 return -EPERM;
847 }
848 break;
849
850 case ANI_MSG_OEM_DATA_REQ:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530851 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800852 "%s: Received Oem Data Request length(%d) from pid: %d",
853 __func__, msg_hdr->length, nlh->nlmsg_pid);
854
855 if ((!p_hdd_ctx->oem_app_registered) ||
856 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
857 /* either oem app is not registered yet or pid is different */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530858 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859 "%s: OEM DataReq: app not registered(%d) or incorrect pid(%d)",
860 __func__, p_hdd_ctx->oem_app_registered,
861 nlh->nlmsg_pid);
862 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
863 OEM_ERR_APP_NOT_REGISTERED);
864 return -EPERM;
865 }
866
867 if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530868 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869 "%s: Invalid length (%d) in Oem Data Request",
870 __func__, msg_hdr->length);
871 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
872 OEM_ERR_INVALID_MESSAGE_LENGTH);
873 return -EPERM;
874 }
875 oem_process_data_req_msg(msg_hdr->length,
876 (char *)((char *)msg_hdr +
877 sizeof(tAniMsgHdr)));
878 break;
879
880 case ANI_MSG_CHANNEL_INFO_REQ:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530881 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882 "%s: Received channel info request, num channel(%d) from pid: %d",
883 __func__, msg_hdr->length, nlh->nlmsg_pid);
884
885 if ((!p_hdd_ctx->oem_app_registered) ||
886 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
887 /* either oem app is not registered yet or pid is different */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530888 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800889 "%s: Chan InfoReq: app not registered(%d) or incorrect pid(%d)",
890 __func__, p_hdd_ctx->oem_app_registered,
891 nlh->nlmsg_pid);
892 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
893 OEM_ERR_APP_NOT_REGISTERED);
894 return -EPERM;
895 }
896
897 /* message length contains list of channel ids */
898 if ((!msg_hdr->length) ||
899 (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530900 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800901 "%s: Invalid length (%d) in channel info request",
902 __func__, msg_hdr->length);
903 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
904 OEM_ERR_INVALID_MESSAGE_LENGTH);
905 return -EPERM;
906 }
907 oem_process_channel_info_req_msg(msg_hdr->length,
908 (char *)((char *)msg_hdr +
909 sizeof(tAniMsgHdr)));
910 break;
911
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800912 case ANI_MSG_SET_OEM_CAP_REQ:
913 hdd_info("Received set oem capability req of length:%d from pid: %d",
914 msg_hdr->length, nlh->nlmsg_pid);
915
916 if ((!p_hdd_ctx->oem_app_registered) ||
917 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
918 /* oem app is not registered yet or pid is different */
919 hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)",
920 p_hdd_ctx->oem_app_registered,
921 nlh->nlmsg_pid);
922 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
923 OEM_ERR_APP_NOT_REGISTERED);
924 return -EPERM;
925 }
926
927 if ((!msg_hdr->length) ||
928 (sizeof(struct sme_oem_capability) < msg_hdr->length)) {
929 hdd_err("Invalid length (%d) in set_oem_capability",
930 msg_hdr->length);
931 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
932 OEM_ERR_INVALID_MESSAGE_LENGTH);
933 return -EPERM;
934 }
935
936 oem_process_set_cap_req_msg(msg_hdr->length,
937 (char *)((char *)msg_hdr +
938 sizeof(tAniMsgHdr)),
939 nlh->nlmsg_pid);
940 break;
941
942 case ANI_MSG_GET_OEM_CAP_REQ:
943 hdd_info("Rcvd get oem capability req of length:%d from pid: %d",
944 msg_hdr->length, nlh->nlmsg_pid);
945
946 if ((!p_hdd_ctx->oem_app_registered) ||
947 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
948 /* oem app is not registered yet or pid is different */
949 hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)",
950 p_hdd_ctx->oem_app_registered,
951 nlh->nlmsg_pid);
952 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
953 OEM_ERR_APP_NOT_REGISTERED);
954 return -EPERM;
955 }
956
957 oem_process_get_cap_req_msg();
958 break;
959
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800960 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530961 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800962 "%s: Received Invalid message type (%d), length (%d)",
963 __func__, msg_hdr->type, msg_hdr->length);
964 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
965 OEM_ERR_INVALID_MESSAGE_TYPE);
966 return -EPERM;
967 }
968 return 0;
969}
970
971static int __oem_msg_callback(struct sk_buff *skb)
972{
973 int ret;
974
975 cds_ssr_protect(__func__);
976 ret = oem_msg_callback(skb);
977 cds_ssr_unprotect(__func__);
978
979 return ret;
980}
981
982/**
983 * oem_activate_service() - Activate oem message handler
984 * @hdd_ctx: pointer to global HDD context
985 *
986 * This function registers a handler to receive netlink message from
987 * an OEM application process.
988 *
989 * Return: zero on success
990 * On error, error number will be returned.
991 */
992int oem_activate_service(struct hdd_context_s *hdd_ctx)
993{
994 p_hdd_ctx = hdd_ctx;
995
996 /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
997 return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback);
998}
999
1000#endif