blob: 1601ce3032a445e0e6a8006df7c0fc585075e51e [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
Jeff Johnsonbfa02062016-05-26 10:09:04 -070037/* denote that this file does not allow legacy hddLog */
38#define HDD_DISALLOW_LEGACY_HDDLOG 1
39
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080040#include <linux/version.h>
41#include <linux/module.h>
42#include <linux/kernel.h>
43#include <linux/init.h>
44#include <linux/wireless.h>
45#include <wlan_hdd_includes.h>
46#include <net/arp.h>
47#include "qwlan_version.h"
48#include "cds_utils.h"
49#include "wma.h"
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080050#include "sme_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080051
52static struct hdd_context_s *p_hdd_ctx;
53
54/**
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080055 * populate_oem_data_cap() - populate oem capabilities
56 * @adapter: device adapter
57 * @data_cap: pointer to populate the capabilities
58 *
59 * Return: error code
60 */
61static int populate_oem_data_cap(hdd_adapter_t *adapter,
62 t_iw_oem_data_cap *data_cap)
63{
Krishna Kumaar Natarajanc4f8a932016-04-16 13:51:42 +053064 QDF_STATUS status;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080065 struct hdd_config *config;
66 uint32_t num_chan;
67 uint8_t *chan_list;
68 hdd_context_t *hdd_ctx = adapter->pHddCtx;
69
70 config = hdd_ctx->config;
71 if (!config) {
72 hdd_err("HDD configuration is null");
73 return -EINVAL;
74 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +053075 chan_list = qdf_mem_malloc(sizeof(uint8_t) * OEM_CAP_MAX_NUM_CHANNELS);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -080076 if (NULL == chan_list) {
77 hdd_err("Memory allocation failed");
78 return -ENOMEM;
79 }
80
81 strlcpy(data_cap->oem_target_signature, OEM_TARGET_SIGNATURE,
82 OEM_TARGET_SIGNATURE_LEN);
83 data_cap->oem_target_type = hdd_ctx->target_type;
84 data_cap->oem_fw_version = hdd_ctx->target_fw_version;
85 data_cap->driver_version.major = QWLAN_VERSION_MAJOR;
86 data_cap->driver_version.minor = QWLAN_VERSION_MINOR;
87 data_cap->driver_version.patch = QWLAN_VERSION_PATCH;
88 data_cap->driver_version.build = QWLAN_VERSION_BUILD;
89 data_cap->allowed_dwell_time_min = config->nNeighborScanMinChanTime;
90 data_cap->allowed_dwell_time_max = config->nNeighborScanMaxChanTime;
91 data_cap->curr_dwell_time_min =
92 sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal,
93 adapter->sessionId);
94 data_cap->curr_dwell_time_max =
95 sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal,
96 adapter->sessionId);
97 data_cap->supported_bands = config->nBandCapability;
98
99 /* request for max num of channels */
Krishna Kumaar Natarajanc4f8a932016-04-16 13:51:42 +0530100 num_chan = OEM_CAP_MAX_NUM_CHANNELS;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800101 status = sme_get_cfg_valid_channels(hdd_ctx->hHal,
102 &chan_list[0], &num_chan);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530103 if (QDF_STATUS_SUCCESS != status) {
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800104 hdd_err("failed to get valid channel list, status: %d", status);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530105 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800106 return -EINVAL;
107 }
108
109 /* make sure num channels is not more than chan list array */
110 if (num_chan > OEM_CAP_MAX_NUM_CHANNELS) {
111 hdd_err("Num of channels-%d > length-%d of chan_list",
112 num_chan, OEM_CAP_MAX_NUM_CHANNELS);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530113 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800114 return -ENOMEM;
115 }
116
117 data_cap->num_channels = num_chan;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530118 qdf_mem_copy(data_cap->channel_list, chan_list,
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800119 sizeof(uint8_t) * num_chan);
120
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530121 qdf_mem_free(chan_list);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800122 return 0;
123}
124
125/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800126 * iw_get_oem_data_cap() - Get OEM Data Capabilities
127 * @dev: net device upon which the request was received
128 * @info: ioctl request information
129 * @wrqu: ioctl request data
130 * @extra: ioctl data payload
131 *
132 * This function gets the capability information for OEM Data Request
133 * and Response.
134 *
135 * Return: 0 for success, negative errno value on failure
136 */
137int iw_get_oem_data_cap(struct net_device *dev,
138 struct iw_request_info *info,
139 union iwreq_data *wrqu, char *extra)
140{
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800141 int status;
142 t_iw_oem_data_cap oemDataCap = { {0} };
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143 t_iw_oem_data_cap *pHddOemDataCap;
144 hdd_adapter_t *pAdapter = (netdev_priv(dev));
145 hdd_context_t *pHddContext;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800146 int ret;
147
148 ENTER();
149
150 pHddContext = WLAN_HDD_GET_CTX(pAdapter);
151 ret = wlan_hdd_validate_context(pHddContext);
152 if (0 != ret)
153 return ret;
154
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800155 status = populate_oem_data_cap(pAdapter, &oemDataCap);
Krishna Kumaar Natarajanbc7e4942016-02-11 15:09:40 -0800156 if (0 != status) {
157 hdd_err("Failed to populate oem data capabilities");
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800158 return status;
Krishna Kumaar Natarajanbc7e4942016-02-11 15:09:40 -0800159 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800160
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800161 pHddOemDataCap = (t_iw_oem_data_cap *) (extra);
162 *pHddOemDataCap = oemDataCap;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800163
164 EXIT();
165 return 0;
166}
167
168/**
169 * send_oem_reg_rsp_nlink_msg() - send oem registration response
170 *
171 * This function sends oem message to registered application process
172 *
173 * Return: none
174 */
175static void send_oem_reg_rsp_nlink_msg(void)
176{
177 struct sk_buff *skb;
178 struct nlmsghdr *nlh;
179 tAniMsgHdr *aniHdr;
180 uint8_t *buf;
181 uint8_t *numInterfaces;
182 uint8_t *deviceMode;
183 uint8_t *vdevId;
184 hdd_adapter_list_node_t *pAdapterNode = NULL;
185 hdd_adapter_list_node_t *pNext = NULL;
186 hdd_adapter_t *pAdapter = NULL;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530187 QDF_STATUS status = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800188
189 /* OEM message is always to a specific process and cannot be a broadcast */
190 if (p_hdd_ctx->oem_pid == 0) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700191 hdd_err("invalid dest pid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800192 return;
193 }
194
195 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
196 if (skb == NULL) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700197 hdd_err("alloc_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800198 return;
199 }
200
201 nlh = (struct nlmsghdr *)skb->data;
202 nlh->nlmsg_pid = 0; /* from kernel */
203 nlh->nlmsg_flags = 0;
204 nlh->nlmsg_seq = 0;
205 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
206 aniHdr = NLMSG_DATA(nlh);
207 aniHdr->type = ANI_MSG_APP_REG_RSP;
208
209 /* Fill message body:
210 * First byte will be number of interfaces, followed by
211 * two bytes for each interfaces
212 * - one byte for device mode
213 * - one byte for vdev id
214 */
215 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
216 numInterfaces = buf++;
217 *numInterfaces = 0;
218
219 /* Iterate through each of the adapters and fill device mode and vdev id */
220 status = hdd_get_front_adapter(p_hdd_ctx, &pAdapterNode);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530221 while ((QDF_STATUS_SUCCESS == status) && pAdapterNode) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800222 pAdapter = pAdapterNode->pAdapter;
223 if (pAdapter) {
224 deviceMode = buf++;
225 vdevId = buf++;
226 *deviceMode = pAdapter->device_mode;
227 *vdevId = pAdapter->sessionId;
228 (*numInterfaces)++;
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700229 hdd_notice("numInterfaces: %d, deviceMode: %d, vdevId: %d",
230 *numInterfaces, *deviceMode,
231 *vdevId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800232 }
233 status = hdd_get_next_adapter(p_hdd_ctx, pAdapterNode, &pNext);
234 pAdapterNode = pNext;
235 }
236
237 aniHdr->length =
238 sizeof(uint8_t) + (*numInterfaces) * 2 * sizeof(uint8_t);
239 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
240
241 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
242
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700243 hdd_notice("sending App Reg Response length (%d) to process pid (%d)",
244 aniHdr->length, p_hdd_ctx->oem_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800245
246 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
247
248 return;
249}
250
251/**
252 * send_oem_err_rsp_nlink_msg() - send oem error response
253 * @app_pid: PID of oem application process
254 * @error_code: response error code
255 *
256 * This function sends error response to oem app
257 *
258 * Return: none
259 */
260static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code)
261{
262 struct sk_buff *skb;
263 struct nlmsghdr *nlh;
264 tAniMsgHdr *aniHdr;
265 uint8_t *buf;
266
267 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
268 if (skb == NULL) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700269 hdd_err("alloc_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800270 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
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700289 hdd_notice("sending oem error response to process pid (%d)", app_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800290
291 (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
292
293 return;
294}
295
296/**
297 * hdd_send_oem_data_rsp_msg() - send oem data response
298 * @length: length of the OEM Data Response message
299 * @oemDataRsp: the actual OEM Data Response message
300 *
301 * This function sends an OEM Data Response message to a registered
302 * application process over the netlink socket.
303 *
304 * Return: 0 for success, non zero for failure
305 */
306void hdd_send_oem_data_rsp_msg(int length, uint8_t *oemDataRsp)
307{
308 struct sk_buff *skb;
309 struct nlmsghdr *nlh;
310 tAniMsgHdr *aniHdr;
311 uint8_t *oemData;
312
313 /* OEM message is always to a specific process and cannot be a broadcast */
314 if (p_hdd_ctx->oem_pid == 0) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700315 hdd_err("invalid dest pid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800316 return;
317 }
318
319 if (length > OEM_DATA_RSP_SIZE) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700320 hdd_err("invalid length of Oem Data response");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800321 return;
322 }
323
324 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + OEM_DATA_RSP_SIZE),
325 GFP_KERNEL);
326 if (skb == NULL) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700327 hdd_err("alloc_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800328 return;
329 }
330
331 nlh = (struct nlmsghdr *)skb->data;
332 nlh->nlmsg_pid = 0; /* from kernel */
333 nlh->nlmsg_flags = 0;
334 nlh->nlmsg_seq = 0;
335 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
336 aniHdr = NLMSG_DATA(nlh);
337 aniHdr->type = ANI_MSG_OEM_DATA_RSP;
338
339 aniHdr->length = length;
340 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
341 oemData = (uint8_t *) ((char *)aniHdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530342 qdf_mem_copy(oemData, oemDataRsp, length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800343
344 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
345
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700346 hdd_notice("sending Oem Data Response of len (%d) to process pid (%d)",
347 length, p_hdd_ctx->oem_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800348
349 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
350
351 return;
352}
353
354/**
355 * oem_process_data_req_msg() - process oem data request
356 * @oemDataLen: Length to OEM Data buffer
357 * @oemData: Pointer to OEM Data buffer
358 *
359 * This function sends oem message to SME
360 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530361 * Return: QDF_STATUS enumeration
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800362 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530363static QDF_STATUS oem_process_data_req_msg(int oemDataLen, char *oemData)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800364{
365 hdd_adapter_t *pAdapter = NULL;
366 tOemDataReqConfig oemDataReqConfig;
367 uint32_t oemDataReqID = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530368 QDF_STATUS status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800369
370 /* for now, STA interface only */
Krunal Sonibe766b02016-03-10 13:00:44 -0800371 pAdapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800372 if (!pAdapter) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700373 hdd_err("No adapter for STA mode");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530374 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800375 }
376
377 if (!oemData) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700378 hdd_err("oemData is null");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530379 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800380 }
381
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530382 qdf_mem_zero(&oemDataReqConfig, sizeof(tOemDataReqConfig));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800383
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530384 oemDataReqConfig.data = qdf_mem_malloc(oemDataLen);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800385 if (!oemDataReqConfig.data) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700386 hdd_err("malloc failed for data req buffer");
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530387 return QDF_STATUS_E_NOMEM;
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800388 }
389
390 oemDataReqConfig.data_len = oemDataLen;
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530391 qdf_mem_copy(oemDataReqConfig.data, oemData, oemDataLen);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800392
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700393 hdd_notice("calling sme_oem_data_req");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800394
395 status = sme_oem_data_req(p_hdd_ctx->hHal,
396 pAdapter->sessionId,
397 &oemDataReqConfig,
Jeff Johnsonf6358f12015-12-07 13:36:10 -0800398 &oemDataReqID);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800399
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530400 qdf_mem_free(oemDataReqConfig.data);
Krishna Kumaar Natarajan9ac8efd2015-11-20 13:40:24 -0800401 oemDataReqConfig.data = NULL;
402
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800403 return status;
404}
405
406/**
Abhishek Singh1c676222016-05-09 14:20:28 +0530407 * update_channel_bw_info() - set bandwidth info for the chan
408 * @hdd_ctx: hdd context
409 * @chan: channel for which info are required
410 * @hdd_chan_info: struct where the bandwidth info is filled
411 *
412 * This function find the maximum bandwidth allowed, secondary
413 * channel offset and center freq for the channel as per regulatory
414 * domain and using these info calculate the phy mode for the
415 * channel.
416 *
417 * Return: void
418 */
419static void hdd_update_channel_bw_info(hdd_context_t *hdd_ctx,
420 uint16_t chan, tHddChannelInfo *hdd_chan_info)
421{
422 struct ch_params_s ch_params = {0};
423 uint16_t sec_ch_2g = 0;
424 WLAN_PHY_MODE phy_mode;
425 uint32_t wni_dot11_mode;
426
427 wni_dot11_mode = sme_get_wni_dot11_mode(hdd_ctx->hHal);
428
429 /* Passing CH_WIDTH_MAX will give the max bandwidth supported */
430 ch_params.ch_width = CH_WIDTH_MAX;
431
432 cds_set_channel_params(chan, sec_ch_2g, &ch_params);
433 if (ch_params.center_freq_seg0)
434 hdd_chan_info->band_center_freq1 =
435 cds_chan_to_freq(ch_params.center_freq_seg0);
436
437 hdd_info("chan %d dot11_mode %d ch_width %d sec offset %d freq_seg0 %d",
438 chan, wni_dot11_mode, ch_params.ch_width,
439 ch_params.sec_ch_offset, hdd_chan_info->band_center_freq1);
440
441 phy_mode = wma_chan_phy_mode(chan, ch_params.ch_width, wni_dot11_mode);
442 WMI_SET_CHANNEL_MODE(hdd_chan_info, phy_mode);
443}
444
445/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800446 * oem_process_channel_info_req_msg() - process oem channel_info request
447 * @numOfChannels: number of channels
448 * @chanList: list of channel information
449 *
450 * This function responds with channel info to oem process
451 *
452 * Return: 0 for success, non zero for failure
453 */
454static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList)
455{
456 struct sk_buff *skb;
457 struct nlmsghdr *nlh;
458 tAniMsgHdr *aniHdr;
459 tHddChannelInfo *pHddChanInfo;
460 tHddChannelInfo hddChanInfo;
461 uint8_t chanId;
462 uint32_t reg_info_1;
463 uint32_t reg_info_2;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530464 QDF_STATUS status = QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800465 int i;
466 uint8_t *buf;
467
468 /* OEM message is always to a specific process and cannot be a broadcast */
469 if (p_hdd_ctx->oem_pid == 0) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700470 hdd_err("invalid dest pid");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800471 return -EPERM;
472 }
473
474 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) +
475 numOfChannels * sizeof(tHddChannelInfo)),
476 GFP_KERNEL);
477 if (skb == NULL) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700478 hdd_err("alloc_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800479 return -ENOMEM;
480 }
481
482 nlh = (struct nlmsghdr *)skb->data;
483 nlh->nlmsg_pid = 0; /* from kernel */
484 nlh->nlmsg_flags = 0;
485 nlh->nlmsg_seq = 0;
486 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
487 aniHdr = NLMSG_DATA(nlh);
488 aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP;
489
490 aniHdr->length =
491 sizeof(uint8_t) + numOfChannels * sizeof(tHddChannelInfo);
492 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
493
494 /* First byte of message body will have num of channels */
495 buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr));
496 *buf++ = numOfChannels;
497
498 /* Next follows channel info struct for each channel id.
499 * If chan id is wrong or SME returns failure for a channel
500 * then fill in 0 in channel info for that particular channel
501 */
502 for (i = 0; i < numOfChannels; i++) {
503 pHddChanInfo = (tHddChannelInfo *) ((char *)buf +
504 i *
505 sizeof(tHddChannelInfo));
506
507 chanId = chanList[i];
508 status = sme_get_reg_info(p_hdd_ctx->hHal, chanId,
509 &reg_info_1, &reg_info_2);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530510 if (QDF_STATUS_SUCCESS == status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800511 /* copy into hdd chan info struct */
512 hddChanInfo.chan_id = chanId;
513 hddChanInfo.reserved0 = 0;
514 hddChanInfo.mhz = cds_chan_to_freq(chanId);
515 hddChanInfo.band_center_freq1 = hddChanInfo.mhz;
516 hddChanInfo.band_center_freq2 = 0;
517
518 hddChanInfo.info = 0;
519 if (CHANNEL_STATE_DFS ==
520 cds_get_channel_state(chanId))
521 WMI_SET_CHANNEL_FLAG(&hddChanInfo,
522 WMI_CHAN_FLAG_DFS);
Abhishek Singh1c676222016-05-09 14:20:28 +0530523
524 hdd_update_channel_bw_info(p_hdd_ctx,
525 chanId, &hddChanInfo);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800526 hddChanInfo.reg_info_1 = reg_info_1;
527 hddChanInfo.reg_info_2 = reg_info_2;
528 } else {
529 /* channel info is not returned, fill in zeros in channel
530 * info struct
531 */
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700532 hdd_notice("sme_get_reg_info failed for chan (%d), return info 0",
533 chanId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800534 hddChanInfo.chan_id = chanId;
535 hddChanInfo.reserved0 = 0;
536 hddChanInfo.mhz = 0;
537 hddChanInfo.band_center_freq1 = 0;
538 hddChanInfo.band_center_freq2 = 0;
539 hddChanInfo.info = 0;
540 hddChanInfo.reg_info_1 = 0;
541 hddChanInfo.reg_info_2 = 0;
542 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530543 qdf_mem_copy(pHddChanInfo, &hddChanInfo,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800544 sizeof(tHddChannelInfo));
545 }
546
547 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
548
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700549 hdd_notice("sending channel info resp for num channels (%d) to pid (%d)",
550 numOfChannels, p_hdd_ctx->oem_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800551
552 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
553
554 return 0;
555}
556
557/**
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800558 * oem_process_set_cap_req_msg() - process oem set capability request
559 * @oem_cap_len: Length of OEM capability
560 * @oem_cap: Pointer to OEM capability buffer
561 * @app_pid: process ID, to which rsp message is to be sent
562 *
563 * This function sends oem message to SME
564 *
565 * Return: error code
566 */
567static int oem_process_set_cap_req_msg(int oem_cap_len,
568 char *oem_cap, int32_t app_pid)
569{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530570 QDF_STATUS status;
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800571 int error_code;
572 struct sk_buff *skb;
573 struct nlmsghdr *nlh;
574 tAniMsgHdr *ani_hdr;
575 uint8_t *buf;
576
577 if (!oem_cap) {
578 hdd_err("oem_cap is null");
579 return -EINVAL;
580 }
581
582 status = sme_oem_update_capability(p_hdd_ctx->hHal,
583 (struct sme_oem_capability *)oem_cap);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530584 if (!QDF_IS_STATUS_SUCCESS(status))
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800585 hdd_err("error updating rm capability, status: %d", status);
Anurag Chouhanc5548422016-02-24 18:33:27 +0530586 error_code = qdf_status_to_os_return(status);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800587
588 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
589 if (skb == NULL) {
590 hdd_err("alloc_skb failed");
591 return -ENOMEM;
592 }
593
594 nlh = (struct nlmsghdr *)skb->data;
595 nlh->nlmsg_pid = 0; /* from kernel */
596 nlh->nlmsg_flags = 0;
597 nlh->nlmsg_seq = 0;
598 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
599 ani_hdr = NLMSG_DATA(nlh);
600 ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP;
601 /* 64 bit alignment */
602 ani_hdr->length = sizeof(error_code);
603 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length);
604
605 /* message body will contain only status code */
606 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530607 qdf_mem_copy(buf, &error_code, ani_hdr->length);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800608
609 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length));
610
611 hdd_info("sending oem response to process pid %d", app_pid);
612
613 (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT);
614
615 return error_code;
616}
617
618/**
619 * oem_process_get_cap_req_msg() - process oem get capability request
620 *
621 * This function process the get capability request from OEM and responds
622 * with the capability.
623 *
624 * Return: error code
625 */
626static int oem_process_get_cap_req_msg(void)
627{
628 int error_code;
629 struct oem_get_capability_rsp *cap_rsp;
630 t_iw_oem_data_cap data_cap = { {0} };
631 struct sme_oem_capability oem_cap;
632 hdd_adapter_t *adapter;
633 struct sk_buff *skb;
634 struct nlmsghdr *nlh;
635 tAniMsgHdr *ani_hdr;
636 uint8_t *buf;
637
638 /* for now, STA interface only */
Krunal Sonibe766b02016-03-10 13:00:44 -0800639 adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800640 if (!adapter) {
641 hdd_err("No adapter for STA mode");
642 return -EINVAL;
643 }
644
645 error_code = populate_oem_data_cap(adapter, &data_cap);
646 if (0 != error_code)
647 return error_code;
648
649 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)),
650 GFP_KERNEL);
651 if (skb == NULL) {
652 hdd_err("alloc_skb failed");
653 return -ENOMEM;
654 }
655
656 nlh = (struct nlmsghdr *)skb->data;
657 nlh->nlmsg_pid = 0; /* from kernel */
658 nlh->nlmsg_flags = 0;
659 nlh->nlmsg_seq = 0;
660 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
661 ani_hdr = NLMSG_DATA(nlh);
662 ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP;
663
664 ani_hdr->length = sizeof(*cap_rsp);
665 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length));
666
667 buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr));
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530668 qdf_mem_copy(buf, &data_cap, sizeof(data_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800669
670 buf = (char *) buf + sizeof(data_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530671 qdf_mem_zero(&oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800672 sme_oem_get_capability(p_hdd_ctx->hHal, &oem_cap);
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530673 qdf_mem_copy(buf, &oem_cap, sizeof(oem_cap));
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800674
675 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length)));
676 hdd_info("send rsp to oem-pid:%d for get_capability",
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700677 p_hdd_ctx->oem_pid);
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800678
679 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
680 return 0;
681}
682
683/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800684 * hdd_send_peer_status_ind_to_oem_app() -
Abhishek Singh1c676222016-05-09 14:20:28 +0530685 * Function to send peer status to a registered application
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800686 * @peerMac: MAC address of peer
687 * @peerStatus: ePeerConnected or ePeerDisconnected
688 * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0
689 * @sessionId: SME session id, i.e. vdev_id
690 * @chan_info: operating channel information
Abhishek Singh1c676222016-05-09 14:20:28 +0530691 * @dev_mode: dev mode for which indication is sent
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800692 *
693 * Return: none
694 */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530695void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800696 uint8_t peerStatus,
697 uint8_t peerTimingMeasCap,
698 uint8_t sessionId,
Abhishek Singh1c676222016-05-09 14:20:28 +0530699 tSirSmeChanInfo *chan_info,
700 enum tQDF_ADAPTER_MODE dev_mode)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800701{
702 struct sk_buff *skb;
703 struct nlmsghdr *nlh;
704 tAniMsgHdr *aniHdr;
705 tPeerStatusInfo *pPeerInfo;
706
707 if (!p_hdd_ctx || !p_hdd_ctx->hHal) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700708 hdd_err("Either HDD Ctx is null or Hal Ctx is null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800709 return;
710 }
711
712 /* check if oem app has registered and pid is valid */
713 if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700714 hdd_info("OEM app is not registered(%d) or pid is invalid(%d)",
715 p_hdd_ctx->oem_app_registered,
716 p_hdd_ctx->oem_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800717 return;
718 }
719
720 skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) +
721 sizeof(tPeerStatusInfo)),
722 GFP_KERNEL);
723 if (skb == NULL) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700724 hdd_err("alloc_skb failed");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800725 return;
726 }
727
728 nlh = (struct nlmsghdr *)skb->data;
729 nlh->nlmsg_pid = 0; /* from kernel */
730 nlh->nlmsg_flags = 0;
731 nlh->nlmsg_seq = 0;
732 nlh->nlmsg_type = WLAN_NL_MSG_OEM;
733 aniHdr = NLMSG_DATA(nlh);
734 aniHdr->type = ANI_MSG_PEER_STATUS_IND;
735
736 aniHdr->length = sizeof(tPeerStatusInfo);
737 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length));
738
739 pPeerInfo = (tPeerStatusInfo *) ((char *)aniHdr + sizeof(tAniMsgHdr));
740
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530741 qdf_mem_copy(pPeerInfo->peer_mac_addr, peerMac->bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742 sizeof(peerMac->bytes));
743 pPeerInfo->peer_status = peerStatus;
744 pPeerInfo->vdev_id = sessionId;
745 pPeerInfo->peer_capability = peerTimingMeasCap;
746 pPeerInfo->reserved0 = 0;
Abhishek Singh1c676222016-05-09 14:20:28 +0530747 /* Set 0th bit of reserved0 for STA mode */
748 if (QDF_STA_MODE == dev_mode)
749 pPeerInfo->reserved0 |= 0x01;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800750
751 if (chan_info) {
752 pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id;
753 pPeerInfo->peer_chan_info.reserved0 = 0;
754 pPeerInfo->peer_chan_info.mhz = chan_info->mhz;
755 pPeerInfo->peer_chan_info.band_center_freq1 =
756 chan_info->band_center_freq1;
757 pPeerInfo->peer_chan_info.band_center_freq2 =
758 chan_info->band_center_freq2;
759 pPeerInfo->peer_chan_info.info = chan_info->info;
760 pPeerInfo->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
761 pPeerInfo->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
762 } else {
763 pPeerInfo->peer_chan_info.chan_id = 0;
764 pPeerInfo->peer_chan_info.reserved0 = 0;
765 pPeerInfo->peer_chan_info.mhz = 0;
766 pPeerInfo->peer_chan_info.band_center_freq1 = 0;
767 pPeerInfo->peer_chan_info.band_center_freq2 = 0;
768 pPeerInfo->peer_chan_info.info = 0;
769 pPeerInfo->peer_chan_info.reg_info_1 = 0;
770 pPeerInfo->peer_chan_info.reg_info_2 = 0;
771 }
772 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length)));
773
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700774 hdd_info("sending peer " MAC_ADDRESS_STR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800775 " status(%d), peerTimingMeasCap(%d), vdevId(%d), chanId(%d)"
776 " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d),"
777 " info (0x%x), frequency (%d),reg info 1 (0x%x),"
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700778 " reg info 2 (0x%x)",
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800779 MAC_ADDR_ARRAY(peerMac->bytes),
780 peerStatus, peerTimingMeasCap,
781 sessionId, pPeerInfo->peer_chan_info.chan_id,
782 p_hdd_ctx->oem_pid,
783 pPeerInfo->peer_chan_info.band_center_freq1,
784 pPeerInfo->peer_chan_info.band_center_freq2,
785 pPeerInfo->peer_chan_info.info,
786 pPeerInfo->peer_chan_info.mhz,
787 pPeerInfo->peer_chan_info.reg_info_1,
788 pPeerInfo->peer_chan_info.reg_info_2);
789
790 (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT);
791
792 return;
793}
794
795/*
796 * Callback function invoked by Netlink service for all netlink
797 * messages (from user space) addressed to WLAN_NL_MSG_OEM
798 */
799
800/**
801 * oem_msg_callback() - callback invoked by netlink service
802 * @skb: skb with netlink message
803 *
804 * This function gets invoked by netlink service when a message
805 * is received from user space addressed to WLAN_NL_MSG_OEM
806 *
807 * Return: zero on success
808 * On error, error number will be returned.
809 */
810static int oem_msg_callback(struct sk_buff *skb)
811{
812 struct nlmsghdr *nlh;
813 tAniMsgHdr *msg_hdr;
814 int ret;
815 char *sign_str = NULL;
816 nlh = (struct nlmsghdr *)skb->data;
817
818 if (!nlh) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700819 hdd_err("Netlink header null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800820 return -EPERM;
821 }
822
823 ret = wlan_hdd_validate_context(p_hdd_ctx);
Abhishek Singh23edd1c2016-05-05 11:56:06 +0530824 if (ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800825 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800826
827 msg_hdr = NLMSG_DATA(nlh);
828
829 if (!msg_hdr) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700830 hdd_err("Message header null");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800831 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
832 OEM_ERR_NULL_MESSAGE_HEADER);
833 return -EPERM;
834 }
835
836 if (nlh->nlmsg_len <
837 NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700838 hdd_err("Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)",
839 nlh->nlmsg_len, msg_hdr->length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800840 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
841 OEM_ERR_INVALID_MESSAGE_LENGTH);
842 return -EPERM;
843 }
844
845 switch (msg_hdr->type) {
846 case ANI_MSG_APP_REG_REQ:
847 /* Registration request is only allowed for Qualcomm Application */
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700848 hdd_notice("Received App Req Req from App process pid(%d), len(%d)",
849 nlh->nlmsg_pid, msg_hdr->length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800850
851 sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr));
852 if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) &&
853 (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR,
854 OEM_APP_SIGNATURE_LEN))) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700855 hdd_notice("Valid App Req Req from oem app process pid(%d)",
856 nlh->nlmsg_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800857
858 p_hdd_ctx->oem_app_registered = true;
859 p_hdd_ctx->oem_pid = nlh->nlmsg_pid;
860 send_oem_reg_rsp_nlink_msg();
861 } else {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700862 hdd_err("Invalid signature in App Reg Request from pid(%d)",
863 nlh->nlmsg_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800864 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
865 OEM_ERR_INVALID_SIGNATURE);
866 return -EPERM;
867 }
868 break;
869
870 case ANI_MSG_OEM_DATA_REQ:
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700871 hdd_notice("Received Oem Data Request length(%d) from pid: %d",
872 msg_hdr->length, nlh->nlmsg_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800873
874 if ((!p_hdd_ctx->oem_app_registered) ||
875 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
876 /* either oem app is not registered yet or pid is different */
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700877 hdd_err("OEM DataReq: app not registered(%d) or incorrect pid(%d)",
878 p_hdd_ctx->oem_app_registered,
879 nlh->nlmsg_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800880 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
881 OEM_ERR_APP_NOT_REGISTERED);
882 return -EPERM;
883 }
884
885 if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700886 hdd_err("Invalid length (%d) in Oem Data Request",
887 msg_hdr->length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
889 OEM_ERR_INVALID_MESSAGE_LENGTH);
890 return -EPERM;
891 }
892 oem_process_data_req_msg(msg_hdr->length,
893 (char *)((char *)msg_hdr +
894 sizeof(tAniMsgHdr)));
895 break;
896
897 case ANI_MSG_CHANNEL_INFO_REQ:
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700898 hdd_notice("Received channel info request, num channel(%d) from pid: %d",
899 msg_hdr->length, nlh->nlmsg_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800900
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 */
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700904 hdd_err("Chan InfoReq: app not registered(%d) or incorrect pid(%d)",
905 p_hdd_ctx->oem_app_registered,
906 nlh->nlmsg_pid);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800907 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
908 OEM_ERR_APP_NOT_REGISTERED);
909 return -EPERM;
910 }
911
912 /* message length contains list of channel ids */
913 if ((!msg_hdr->length) ||
914 (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) {
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700915 hdd_err("Invalid length (%d) in channel info request",
916 msg_hdr->length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800917 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
918 OEM_ERR_INVALID_MESSAGE_LENGTH);
919 return -EPERM;
920 }
921 oem_process_channel_info_req_msg(msg_hdr->length,
922 (char *)((char *)msg_hdr +
923 sizeof(tAniMsgHdr)));
924 break;
925
Krishna Kumaar Natarajan53ca2902015-12-04 14:01:46 -0800926 case ANI_MSG_SET_OEM_CAP_REQ:
927 hdd_info("Received set oem capability req of length:%d from pid: %d",
928 msg_hdr->length, nlh->nlmsg_pid);
929
930 if ((!p_hdd_ctx->oem_app_registered) ||
931 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
932 /* oem app is not registered yet or pid is different */
933 hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)",
934 p_hdd_ctx->oem_app_registered,
935 nlh->nlmsg_pid);
936 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
937 OEM_ERR_APP_NOT_REGISTERED);
938 return -EPERM;
939 }
940
941 if ((!msg_hdr->length) ||
942 (sizeof(struct sme_oem_capability) < msg_hdr->length)) {
943 hdd_err("Invalid length (%d) in set_oem_capability",
944 msg_hdr->length);
945 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
946 OEM_ERR_INVALID_MESSAGE_LENGTH);
947 return -EPERM;
948 }
949
950 oem_process_set_cap_req_msg(msg_hdr->length,
951 (char *)((char *)msg_hdr +
952 sizeof(tAniMsgHdr)),
953 nlh->nlmsg_pid);
954 break;
955
956 case ANI_MSG_GET_OEM_CAP_REQ:
957 hdd_info("Rcvd get oem capability req of length:%d from pid: %d",
958 msg_hdr->length, nlh->nlmsg_pid);
959
960 if ((!p_hdd_ctx->oem_app_registered) ||
961 (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) {
962 /* oem app is not registered yet or pid is different */
963 hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)",
964 p_hdd_ctx->oem_app_registered,
965 nlh->nlmsg_pid);
966 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
967 OEM_ERR_APP_NOT_REGISTERED);
968 return -EPERM;
969 }
970
971 oem_process_get_cap_req_msg();
972 break;
973
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800974 default:
Jeff Johnsonbfa02062016-05-26 10:09:04 -0700975 hdd_err("Received Invalid message type (%d), length (%d)",
976 msg_hdr->type, msg_hdr->length);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800977 send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid,
978 OEM_ERR_INVALID_MESSAGE_TYPE);
979 return -EPERM;
980 }
981 return 0;
982}
983
984static int __oem_msg_callback(struct sk_buff *skb)
985{
986 int ret;
987
988 cds_ssr_protect(__func__);
989 ret = oem_msg_callback(skb);
990 cds_ssr_unprotect(__func__);
991
992 return ret;
993}
994
995/**
996 * oem_activate_service() - Activate oem message handler
997 * @hdd_ctx: pointer to global HDD context
998 *
999 * This function registers a handler to receive netlink message from
1000 * an OEM application process.
1001 *
1002 * Return: zero on success
1003 * On error, error number will be returned.
1004 */
1005int oem_activate_service(struct hdd_context_s *hdd_ctx)
1006{
1007 p_hdd_ctx = hdd_ctx;
1008
1009 /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */
1010 return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback);
1011}
1012
1013#endif