blob: 7452022d8db92b178f950c10e0e33135692ab5ba [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{
Krishna Kumaar Natarajanc4f8a932016-04-16 13:51:42 +053061 QDF_STATUS status;
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 */
Krishna Kumaar Natarajanc4f8a932016-04-16 13:51:42 +053097 num_chan = OEM_CAP_MAX_NUM_CHANNELS;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080098 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/**
Abhishek Singh1c676222016-05-09 14:20:28 +0530418 * update_channel_bw_info() - set bandwidth info for the chan
419 * @hdd_ctx: hdd context
420 * @chan: channel for which info are required
421 * @hdd_chan_info: struct where the bandwidth info is filled
422 *
423 * This function find the maximum bandwidth allowed, secondary
424 * channel offset and center freq for the channel as per regulatory
425 * domain and using these info calculate the phy mode for the
426 * channel.
427 *
428 * Return: void
429 */
430static void hdd_update_channel_bw_info(hdd_context_t *hdd_ctx,
431 uint16_t chan, tHddChannelInfo *hdd_chan_info)
432{
433 struct ch_params_s ch_params = {0};
434 uint16_t sec_ch_2g = 0;
435 WLAN_PHY_MODE phy_mode;
436 uint32_t wni_dot11_mode;
437
438 wni_dot11_mode = sme_get_wni_dot11_mode(hdd_ctx->hHal);
439
440 /* Passing CH_WIDTH_MAX will give the max bandwidth supported */
441 ch_params.ch_width = CH_WIDTH_MAX;
442
443 cds_set_channel_params(chan, sec_ch_2g, &ch_params);
444 if (ch_params.center_freq_seg0)
445 hdd_chan_info->band_center_freq1 =
446 cds_chan_to_freq(ch_params.center_freq_seg0);
447
448 hdd_info("chan %d dot11_mode %d ch_width %d sec offset %d freq_seg0 %d",
449 chan, wni_dot11_mode, ch_params.ch_width,
450 ch_params.sec_ch_offset, hdd_chan_info->band_center_freq1);
451
452 phy_mode = wma_chan_phy_mode(chan, ch_params.ch_width, wni_dot11_mode);
453 WMI_SET_CHANNEL_MODE(hdd_chan_info, phy_mode);
454}
455
456/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800457 * oem_process_channel_info_req_msg() - process oem channel_info request
458 * @numOfChannels: number of channels
459 * @chanList: list of channel information
460 *
461 * This function responds with channel info to oem process
462 *
463 * Return: 0 for success, non zero for failure
464 */
465static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList)
466{
467 struct sk_buff *skb;
468 struct nlmsghdr *nlh;
469 tAniMsgHdr *aniHdr;
470 tHddChannelInfo *pHddChanInfo;
471 tHddChannelInfo hddChanInfo;
472 uint8_t chanId;
473 uint32_t reg_info_1;
474 uint32_t reg_info_2;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530475 QDF_STATUS status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 int i;
477 uint8_t *buf;
478
479 /* OEM message is always to a specific process and cannot be a broadcast */
480 if (p_hdd_ctx->oem_pid == 0) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530481 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800482 "%s: invalid dest pid", __func__);
483 return -EPERM;
484 }
485
486 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) +
487 numOfChannels * sizeof(tHddChannelInfo)),
488 GFP_KERNEL);
489 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530490 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800491 "%s: alloc_skb failed", __func__);
492 return -ENOMEM;
493 }
494
495 nlh = (struct nlmsghdr *)skb->data;
496 nlh->nlmsg_pid = 0; /* from kernel */
497 nlh->nlmsg_flags = 0;
498 nlh->nlmsg_seq = 0;
499 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
500 aniHdr = NLMSG_DATA(nlh);
501 aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP;
502
503 aniHdr->length =
504 sizeof(uint8_t) + numOfChannels * sizeof(tHddChannelInfo);
505 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
506
507 /* First byte of message body will have num of channels */
508 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
509 *buf++ = numOfChannels;
510
511 /* Next follows channel info struct for each channel id.
512 * If chan id is wrong or SME returns failure for a channel
513 * then fill in 0 in channel info for that particular channel
514 */
515 for (i = 0; i < numOfChannels; i++) {
516 pHddChanInfo = (tHddChannelInfo *) ((char *)buf +
517 i *
518 sizeof(tHddChannelInfo));
519
520 chanId = chanList[i];
521 status = sme_get_reg_info(p_hdd_ctx->hHal, chanId,
522 &reg_info_1, &reg_info_2);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530523 if (QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800524 /* copy into hdd chan info struct */
525 hddChanInfo.chan_id = chanId;
526 hddChanInfo.reserved0 = 0;
527 hddChanInfo.mhz = cds_chan_to_freq(chanId);
528 hddChanInfo.band_center_freq1 = hddChanInfo.mhz;
529 hddChanInfo.band_center_freq2 = 0;
530
531 hddChanInfo.info = 0;
532 if (CHANNEL_STATE_DFS ==
533 cds_get_channel_state(chanId))
534 WMI_SET_CHANNEL_FLAG(&hddChanInfo,
535 WMI_CHAN_FLAG_DFS);
Abhishek Singh1c676222016-05-09 14:20:28 +0530536
537 hdd_update_channel_bw_info(p_hdd_ctx,
538 chanId, &hddChanInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800539 hddChanInfo.reg_info_1 = reg_info_1;
540 hddChanInfo.reg_info_2 = reg_info_2;
541 } else {
542 /* channel info is not returned, fill in zeros in channel
543 * info struct
544 */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530545 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800546 "%s: sme_get_reg_info failed for chan (%d), return info 0",
547 __func__, chanId);
548 hddChanInfo.chan_id = chanId;
549 hddChanInfo.reserved0 = 0;
550 hddChanInfo.mhz = 0;
551 hddChanInfo.band_center_freq1 = 0;
552 hddChanInfo.band_center_freq2 = 0;
553 hddChanInfo.info = 0;
554 hddChanInfo.reg_info_1 = 0;
555 hddChanInfo.reg_info_2 = 0;
556 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530557 qdf_mem_copy(pHddChanInfo, &hddChanInfo,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800558 sizeof(tHddChannelInfo));
559 }
560
561 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
562
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530563 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800564 "%s: sending channel info resp for num channels (%d) to pid (%d)",
565 __func__, numOfChannels, p_hdd_ctx->oem_pid);
566
567 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
568
569 return 0;
570}
571
572/**
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800573 * oem_process_set_cap_req_msg() - process oem set capability request
574 * @oem_cap_len: Length of OEM capability
575 * @oem_cap: Pointer to OEM capability buffer
576 * @app_pid: process ID, to which rsp message is to be sent
577 *
578 * This function sends oem message to SME
579 *
580 * Return: error code
581 */
582static int oem_process_set_cap_req_msg(int oem_cap_len,
583 char *oem_cap, int32_t app_pid)
584{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530585 QDF_STATUS status;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800586 int error_code;
587 struct sk_buff *skb;
588 struct nlmsghdr *nlh;
589 tAniMsgHdr *ani_hdr;
590 uint8_t *buf;
591
592 if (!oem_cap) {
593 hdd_err("oem_cap is null");
594 return -EINVAL;
595 }
596
597 status = sme_oem_update_capability(p_hdd_ctx->hHal,
598 (struct sme_oem_capability *)oem_cap);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530599 if (!QDF_IS_STATUS_SUCCESS(status))
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800600 hdd_err("error updating rm capability, status: %d", status);
Anurag Chouhanc5548422016-02-24 18:33:27 +0530601 error_code = qdf_status_to_os_return(status);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800602
603 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
604 if (skb == NULL) {
605 hdd_err("alloc_skb failed");
606 return -ENOMEM;
607 }
608
609 nlh = (struct nlmsghdr *)skb->data;
610 nlh->nlmsg_pid = 0; /* from kernel */
611 nlh->nlmsg_flags = 0;
612 nlh->nlmsg_seq = 0;
613 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
614 ani_hdr = NLMSG_DATA(nlh);
615 ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP;
616 /* 64 bit alignment */
617 ani_hdr->length = sizeof(error_code);
618 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length);
619
620 /* message body will contain only status code */
621 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530622 qdf_mem_copy(buf, &error_code, ani_hdr->length);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800623
624 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length));
625
626 hdd_info("sending oem response to process pid %d", app_pid);
627
628 (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
629
630 return error_code;
631}
632
633/**
634 * oem_process_get_cap_req_msg() - process oem get capability request
635 *
636 * This function process the get capability request from OEM and responds
637 * with the capability.
638 *
639 * Return: error code
640 */
641static int oem_process_get_cap_req_msg(void)
642{
643 int error_code;
644 struct oem_get_capability_rsp *cap_rsp;
645 t_iw_oem_data_cap data_cap = { {0} };
646 struct sme_oem_capability oem_cap;
647 hdd_adapter_t *adapter;
648 struct sk_buff *skb;
649 struct nlmsghdr *nlh;
650 tAniMsgHdr *ani_hdr;
651 uint8_t *buf;
652
653 /* for now, STA interface only */
Krunal Sonibe766b02016-03-10 13:00:44 -0800654 adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800655 if (!adapter) {
656 hdd_err("No adapter for STA mode");
657 return -EINVAL;
658 }
659
660 error_code = populate_oem_data_cap(adapter, &data_cap);
661 if (0 != error_code)
662 return error_code;
663
664 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)),
665 GFP_KERNEL);
666 if (skb == NULL) {
667 hdd_err("alloc_skb failed");
668 return -ENOMEM;
669 }
670
671 nlh = (struct nlmsghdr *)skb->data;
672 nlh->nlmsg_pid = 0; /* from kernel */
673 nlh->nlmsg_flags = 0;
674 nlh->nlmsg_seq = 0;
675 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
676 ani_hdr = NLMSG_DATA(nlh);
677 ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP;
678
679 ani_hdr->length = sizeof(*cap_rsp);
680 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
681
682 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530683 qdf_mem_copy(buf, &data_cap, sizeof(data_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800684
685 buf = (char *) buf + sizeof(data_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530686 qdf_mem_zero(&oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800687 sme_oem_get_capability(p_hdd_ctx->hHal, &oem_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530688 qdf_mem_copy(buf, &oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800689
690 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
691 hdd_info("send rsp to oem-pid:%d for get_capability",
692 p_hdd_ctx->oem_pid);
693
694 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
695 return 0;
696}
697
698/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800699 * hdd_send_peer_status_ind_to_oem_app() -
Abhishek Singh1c676222016-05-09 14:20:28 +0530700 * Function to send peer status to a registered application
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800701 * @peerMac: MAC address of peer
702 * @peerStatus: ePeerConnected or ePeerDisconnected
703 * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0
704 * @sessionId: SME session id, i.e. vdev_id
705 * @chan_info: operating channel information
Abhishek Singh1c676222016-05-09 14:20:28 +0530706 * @dev_mode: dev mode for which indication is sent
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800707 *
708 * Return: none
709 */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530710void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800711 uint8_t peerStatus,
712 uint8_t peerTimingMeasCap,
713 uint8_t sessionId,
Abhishek Singh1c676222016-05-09 14:20:28 +0530714 tSirSmeChanInfo *chan_info,
715 enum tQDF_ADAPTER_MODE dev_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800716{
717 struct sk_buff *skb;
718 struct nlmsghdr *nlh;
719 tAniMsgHdr *aniHdr;
720 tPeerStatusInfo *pPeerInfo;
721
722 if (!p_hdd_ctx || !p_hdd_ctx->hHal) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530723 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800724 "%s: Either HDD Ctx is null or Hal Ctx is null",
725 __func__);
726 return;
727 }
728
729 /* check if oem app has registered and pid is valid */
730 if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530731 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732 "%s: OEM app is not registered(%d) or pid is invalid(%d)",
733 __func__, p_hdd_ctx->oem_app_registered,
734 p_hdd_ctx->oem_pid);
735 return;
736 }
737
738 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) +
739 sizeof(tPeerStatusInfo)),
740 GFP_KERNEL);
741 if (skb == NULL) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530742 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800743 "%s: alloc_skb failed", __func__);
744 return;
745 }
746
747 nlh = (struct nlmsghdr *)skb->data;
748 nlh->nlmsg_pid = 0; /* from kernel */
749 nlh->nlmsg_flags = 0;
750 nlh->nlmsg_seq = 0;
751 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
752 aniHdr = NLMSG_DATA(nlh);
753 aniHdr->type = ANI_MSG_PEER_STATUS_IND;
754
755 aniHdr->length = sizeof(tPeerStatusInfo);
756 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
757
758 pPeerInfo = (tPeerStatusInfo *) ((char *)aniHdr + sizeof(tAniMsgHdr));
759
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530760 qdf_mem_copy(pPeerInfo->peer_mac_addr, peerMac->bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761 sizeof(peerMac->bytes));
762 pPeerInfo->peer_status = peerStatus;
763 pPeerInfo->vdev_id = sessionId;
764 pPeerInfo->peer_capability = peerTimingMeasCap;
765 pPeerInfo->reserved0 = 0;
Abhishek Singh1c676222016-05-09 14:20:28 +0530766 /* Set 0th bit of reserved0 for STA mode */
767 if (QDF_STA_MODE == dev_mode)
768 pPeerInfo->reserved0 |= 0x01;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800769
770 if (chan_info) {
771 pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id;
772 pPeerInfo->peer_chan_info.reserved0 = 0;
773 pPeerInfo->peer_chan_info.mhz = chan_info->mhz;
774 pPeerInfo->peer_chan_info.band_center_freq1 =
775 chan_info->band_center_freq1;
776 pPeerInfo->peer_chan_info.band_center_freq2 =
777 chan_info->band_center_freq2;
778 pPeerInfo->peer_chan_info.info = chan_info->info;
779 pPeerInfo->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
780 pPeerInfo->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
781 } else {
782 pPeerInfo->peer_chan_info.chan_id = 0;
783 pPeerInfo->peer_chan_info.reserved0 = 0;
784 pPeerInfo->peer_chan_info.mhz = 0;
785 pPeerInfo->peer_chan_info.band_center_freq1 = 0;
786 pPeerInfo->peer_chan_info.band_center_freq2 = 0;
787 pPeerInfo->peer_chan_info.info = 0;
788 pPeerInfo->peer_chan_info.reg_info_1 = 0;
789 pPeerInfo->peer_chan_info.reg_info_2 = 0;
790 }
791 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
792
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530793 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800794 "%s: sending peer " MAC_ADDRESS_STR
795 " status(%d), peerTimingMeasCap(%d), vdevId(%d), chanId(%d)"
796 " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d),"
797 " info (0x%x), frequency (%d),reg info 1 (0x%x),"
798 " reg info 2 (0x%x)", __func__,
799 MAC_ADDR_ARRAY(peerMac->bytes),
800 peerStatus, peerTimingMeasCap,
801 sessionId, pPeerInfo->peer_chan_info.chan_id,
802 p_hdd_ctx->oem_pid,
803 pPeerInfo->peer_chan_info.band_center_freq1,
804 pPeerInfo->peer_chan_info.band_center_freq2,
805 pPeerInfo->peer_chan_info.info,
806 pPeerInfo->peer_chan_info.mhz,
807 pPeerInfo->peer_chan_info.reg_info_1,
808 pPeerInfo->peer_chan_info.reg_info_2);
809
810 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
811
812 return;
813}
814
815/*
816 * Callback function invoked by Netlink service for all netlink
817 * messages (from user space) addressed to WLAN_NL_MSG_OEM
818 */
819
820/**
821 * oem_msg_callback() - callback invoked by netlink service
822 * @skb: skb with netlink message
823 *
824 * This function gets invoked by netlink service when a message
825 * is received from user space addressed to WLAN_NL_MSG_OEM
826 *
827 * Return: zero on success
828 * On error, error number will be returned.
829 */
830static int oem_msg_callback(struct sk_buff *skb)
831{
832 struct nlmsghdr *nlh;
833 tAniMsgHdr *msg_hdr;
834 int ret;
835 char *sign_str = NULL;
836 nlh = (struct nlmsghdr *)skb->data;
837
838 if (!nlh) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530839 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 "%s: Netlink header null", __func__);
841 return -EPERM;
842 }
843
844 ret = wlan_hdd_validate_context(p_hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530845 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847
848 msg_hdr = NLMSG_DATA(nlh);
849
850 if (!msg_hdr) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530851 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800852 "%s: Message header null", __func__);
853 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
854 OEM_ERR_NULL_MESSAGE_HEADER);
855 return -EPERM;
856 }
857
858 if (nlh->nlmsg_len <
859 NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) {
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: Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)",
862 __func__, nlh->nlmsg_len, msg_hdr->length);
863 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
864 OEM_ERR_INVALID_MESSAGE_LENGTH);
865 return -EPERM;
866 }
867
868 switch (msg_hdr->type) {
869 case ANI_MSG_APP_REG_REQ:
870 /* Registration request is only allowed for Qualcomm Application */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530871 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800872 "%s: Received App Req Req from App process pid(%d), len(%d)",
873 __func__, nlh->nlmsg_pid, msg_hdr->length);
874
875 sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr));
876 if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) &&
877 (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR,
878 OEM_APP_SIGNATURE_LEN))) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530879 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800880 "%s: Valid App Req Req from oem app process pid(%d)",
881 __func__, nlh->nlmsg_pid);
882
883 p_hdd_ctx->oem_app_registered = true;
884 p_hdd_ctx->oem_pid = nlh->nlmsg_pid;
885 send_oem_reg_rsp_nlink_msg();
886 } else {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530887 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 "%s: Invalid signature in App Reg Request from pid(%d)",
889 __func__, nlh->nlmsg_pid);
890 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
891 OEM_ERR_INVALID_SIGNATURE);
892 return -EPERM;
893 }
894 break;
895
896 case ANI_MSG_OEM_DATA_REQ:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530897 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800898 "%s: Received Oem Data Request length(%d) from pid: %d",
899 __func__, msg_hdr->length, nlh->nlmsg_pid);
900
901 if ((!p_hdd_ctx->oem_app_registered) ||
902 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
903 /* either oem app is not registered yet or pid is different */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530904 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800905 "%s: OEM DataReq: app not registered(%d) or incorrect pid(%d)",
906 __func__, p_hdd_ctx->oem_app_registered,
907 nlh->nlmsg_pid);
908 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
909 OEM_ERR_APP_NOT_REGISTERED);
910 return -EPERM;
911 }
912
913 if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530914 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800915 "%s: Invalid length (%d) in Oem Data Request",
916 __func__, msg_hdr->length);
917 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
918 OEM_ERR_INVALID_MESSAGE_LENGTH);
919 return -EPERM;
920 }
921 oem_process_data_req_msg(msg_hdr->length,
922 (char *)((char *)msg_hdr +
923 sizeof(tAniMsgHdr)));
924 break;
925
926 case ANI_MSG_CHANNEL_INFO_REQ:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530927 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800928 "%s: Received channel info request, num channel(%d) from pid: %d",
929 __func__, msg_hdr->length, nlh->nlmsg_pid);
930
931 if ((!p_hdd_ctx->oem_app_registered) ||
932 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
933 /* either oem app is not registered yet or pid is different */
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530934 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800935 "%s: Chan InfoReq: app not registered(%d) or incorrect pid(%d)",
936 __func__, p_hdd_ctx->oem_app_registered,
937 nlh->nlmsg_pid);
938 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
939 OEM_ERR_APP_NOT_REGISTERED);
940 return -EPERM;
941 }
942
943 /* message length contains list of channel ids */
944 if ((!msg_hdr->length) ||
945 (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) {
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +0530946 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800947 "%s: Invalid length (%d) in channel info request",
948 __func__, msg_hdr->length);
949 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
950 OEM_ERR_INVALID_MESSAGE_LENGTH);
951 return -EPERM;
952 }
953 oem_process_channel_info_req_msg(msg_hdr->length,
954 (char *)((char *)msg_hdr +
955 sizeof(tAniMsgHdr)));
956 break;
957
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800958 case ANI_MSG_SET_OEM_CAP_REQ:
959 hdd_info("Received set oem capability req of length:%d from pid: %d",
960 msg_hdr->length, nlh->nlmsg_pid);
961
962 if ((!p_hdd_ctx->oem_app_registered) ||
963 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
964 /* oem app is not registered yet or pid is different */
965 hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)",
966 p_hdd_ctx->oem_app_registered,
967 nlh->nlmsg_pid);
968 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
969 OEM_ERR_APP_NOT_REGISTERED);
970 return -EPERM;
971 }
972
973 if ((!msg_hdr->length) ||
974 (sizeof(struct sme_oem_capability) < msg_hdr->length)) {
975 hdd_err("Invalid length (%d) in set_oem_capability",
976 msg_hdr->length);
977 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
978 OEM_ERR_INVALID_MESSAGE_LENGTH);
979 return -EPERM;
980 }
981
982 oem_process_set_cap_req_msg(msg_hdr->length,
983 (char *)((char *)msg_hdr +
984 sizeof(tAniMsgHdr)),
985 nlh->nlmsg_pid);
986 break;
987
988 case ANI_MSG_GET_OEM_CAP_REQ:
989 hdd_info("Rcvd get oem capability req of length:%d from pid: %d",
990 msg_hdr->length, nlh->nlmsg_pid);
991
992 if ((!p_hdd_ctx->oem_app_registered) ||
993 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
994 /* oem app is not registered yet or pid is different */
995 hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)",
996 p_hdd_ctx->oem_app_registered,
997 nlh->nlmsg_pid);
998 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
999 OEM_ERR_APP_NOT_REGISTERED);
1000 return -EPERM;
1001 }
1002
1003 oem_process_get_cap_req_msg();
1004 break;
1005
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001006 default:
Anurag Chouhanb2dc16f2016-02-25 11:47:37 +05301007 QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001008 "%s: Received Invalid message type (%d), length (%d)",
1009 __func__, msg_hdr->type, msg_hdr->length);
1010 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
1011 OEM_ERR_INVALID_MESSAGE_TYPE);
1012 return -EPERM;
1013 }
1014 return 0;
1015}
1016
1017static int __oem_msg_callback(struct sk_buff *skb)
1018{
1019 int ret;
1020
1021 cds_ssr_protect(__func__);
1022 ret = oem_msg_callback(skb);
1023 cds_ssr_unprotect(__func__);
1024
1025 return ret;
1026}
1027
1028/**
1029 * oem_activate_service() - Activate oem message handler
1030 * @hdd_ctx: pointer to global HDD context
1031 *
1032 * This function registers a handler to receive netlink message from
1033 * an OEM application process.
1034 *
1035 * Return: zero on success
1036 * On error, error number will be returned.
1037 */
1038int oem_activate_service(struct hdd_context_s *hdd_ctx)
1039{
1040 p_hdd_ctx = hdd_ctx;
1041
1042 /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
1043 return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback);
1044}
1045
1046#endif