xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/wifi_pos/src/os_if_wifi_pos.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: wlan_hdd_wifi_pos.c
21  * This file defines the important functions pertinent to wifi positioning
22  * component's os_if layer.
23  */
24 
25 #include "qdf_platform.h"
26 #include "qdf_module.h"
27 #include "wlan_nlink_srv.h"
28 #include "wlan_ptt_sock_svc.h"
29 #include "wlan_nlink_common.h"
30 #include "os_if_wifi_pos.h"
31 #include "wifi_pos_api.h"
32 #include "wlan_cfg80211.h"
33 #include "wlan_objmgr_psoc_obj.h"
34 #ifdef CNSS_GENL
35 #include <net/cnss_nl.h>
36 #endif
37 
38 /**
39  * os_if_wifi_pos_send_rsp() - send oem registration response
40  *
41  * This function sends oem message to registered application process
42  *
43  * Return:  none
44  */
45 static void os_if_wifi_pos_send_rsp(uint32_t pid, uint32_t rsp_msg_type,
46 				    uint32_t buf_len, uint8_t *buf)
47 {
48 	tAniMsgHdr *aniHdr;
49 	struct sk_buff *skb;
50 	struct nlmsghdr *nlh;
51 
52 	/* OEM msg is always to a specific process and cannot be a broadcast */
53 	if (pid == 0) {
54 		osif_err("invalid dest pid");
55 		return;
56 	}
57 
58 	skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len), GFP_ATOMIC);
59 	if (!skb) {
60 		osif_alert("alloc_skb failed");
61 		return;
62 	}
63 
64 	nlh = (struct nlmsghdr *)skb->data;
65 	nlh->nlmsg_pid = 0;     /* from kernel */
66 	nlh->nlmsg_flags = 0;
67 	nlh->nlmsg_seq = 0;
68 	nlh->nlmsg_type = WLAN_NL_MSG_OEM;
69 	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + buf_len);
70 
71 	aniHdr = NLMSG_DATA(nlh);
72 	aniHdr->type = rsp_msg_type;
73 	qdf_mem_copy(&aniHdr[1], buf, buf_len);
74 	aniHdr->length = buf_len;
75 
76 	skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + buf_len));
77 	osif_debug("sending oem rsp: type: %d len(%d) to pid (%d)",
78 		   rsp_msg_type, buf_len, pid);
79 	nl_srv_ucast_oem(skb, pid, MSG_DONTWAIT);
80 }
81 
82 #ifdef CNSS_GENL
83 static int  wifi_pos_parse_req(const void *data, int len, int pid,
84 		    struct wifi_pos_req_msg *req)
85 {
86 	tAniMsgHdr *msg_hdr;
87 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
88 	uint32_t msg_len, id, nl_field_info_size, expected_field_info_size;
89 	struct wifi_pos_field_info *field_info;
90 
91 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, len, NULL)) {
92 		osif_err("invalid data in request");
93 		return OEM_ERR_INVALID_MESSAGE_TYPE;
94 	}
95 
96 	if (!tb[CLD80211_ATTR_DATA]) {
97 		osif_err("CLD80211_ATTR_DATA not present");
98 		return OEM_ERR_INVALID_MESSAGE_TYPE;
99 	}
100 
101 	msg_len = nla_len(tb[CLD80211_ATTR_DATA]);
102 	if (msg_len < sizeof(*msg_hdr)) {
103 		osif_err("Insufficient length for msg_hdr: %u", msg_len);
104 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
105 	}
106 
107 	msg_hdr = nla_data(tb[CLD80211_ATTR_DATA]);
108 	req->msg_type = msg_hdr->type;
109 
110 	if (msg_len < sizeof(*msg_hdr) + msg_hdr->length) {
111 		osif_err("Insufficient length for msg_hdr buffer: %u",
112 			 msg_len);
113 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
114 	}
115 
116 	req->buf_len = msg_hdr->length;
117 	req->buf = (uint8_t *)&msg_hdr[1];
118 	req->pid = pid;
119 
120 	id = CLD80211_ATTR_META_DATA;
121 	if (!tb[id])
122 		return 0;
123 
124 	nl_field_info_size = nla_len(tb[id]);
125 	if (nl_field_info_size < sizeof(*field_info)) {
126 		osif_err("Insufficient length for field_info_buf: %u",
127 			 nl_field_info_size);
128 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
129 	}
130 
131 	field_info = nla_data(tb[id]);
132 	if (!field_info->count) {
133 		osif_debug("field_info->count is zero, ignoring META_DATA");
134 		return 0;
135 	}
136 
137 	expected_field_info_size = sizeof(*field_info) +
138 		(field_info->count - 1) * sizeof(struct wifi_pos_field);
139 
140 	if (nl_field_info_size < expected_field_info_size) {
141 		osif_err("Insufficient len for total no.of %u fields",
142 			 field_info->count);
143 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
144 	}
145 
146 	req->field_info_buf = field_info;
147 	req->field_info_buf_len = nl_field_info_size;
148 
149 	return 0;
150 }
151 #else
152 static int wifi_pos_parse_req(struct sk_buff *skb, struct wifi_pos_req_msg *req)
153 {
154 	/* SKB->data contains NL msg */
155 	/* NLMSG_DATA(nlh) contains ANI msg */
156 	struct nlmsghdr *nlh;
157 	tAniMsgHdr *msg_hdr;
158 	size_t field_info_len;
159 
160 	nlh = (struct nlmsghdr *)skb->data;
161 	if (!nlh) {
162 		osif_err("Netlink header null");
163 		return OEM_ERR_NULL_MESSAGE_HEADER;
164 	}
165 
166 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr))) {
167 		osif_err("nlmsg_len(%d) and msg_hdr_size(%zu) mis-match",
168 			 nlh->nlmsg_len, sizeof(*msg_hdr));
169 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
170 	}
171 
172 	msg_hdr = NLMSG_DATA(nlh);
173 	if (!msg_hdr) {
174 		osif_err("Message header null");
175 		return OEM_ERR_NULL_MESSAGE_HEADER;
176 	}
177 
178 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length)) {
179 		osif_err("nlmsg_len(%d) and animsg_len(%d) mis-match",
180 			 nlh->nlmsg_len, msg_hdr->length);
181 		return OEM_ERR_INVALID_MESSAGE_LENGTH;
182 	}
183 
184 	req->msg_type = msg_hdr->type;
185 	req->buf_len = msg_hdr->length;
186 	req->buf = (uint8_t *)&msg_hdr[1];
187 	req->pid = nlh->nlmsg_pid;
188 	req->field_info_buf = NULL;
189 
190 	field_info_len = nlh->nlmsg_len -
191 			(NLMSG_LENGTH(sizeof(*msg_hdr) + msg_hdr->length));
192 	if (field_info_len) {
193 		req->field_info_buf = (struct wifi_pos_field_info *)
194 				      (req->buf + req->buf_len);
195 		req->field_info_buf_len = field_info_len;
196 	}
197 
198 	return 0;
199 }
200 #endif
201 
202 /**
203  * __os_if_wifi_pos_callback() - callback registered with NL service socket to
204  * process wifi pos request
205  * @skb: request message sk_buff
206  *
207  * Return: status of operation
208  */
209 #ifdef CNSS_GENL
210 static void __os_if_wifi_pos_callback(const void *data, int data_len,
211 				      void *ctx, int pid)
212 {
213 	uint8_t err;
214 	QDF_STATUS status;
215 	struct wifi_pos_req_msg req = {0};
216 	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
217 
218 	osif_debug("enter: pid %d", pid);
219 	if (!psoc) {
220 		osif_err("global psoc object not registered yet.");
221 		return;
222 	}
223 
224 	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
225 	err = wifi_pos_parse_req(data, data_len, pid, &req);
226 	if (err) {
227 		os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc),
228 					ANI_MSG_OEM_ERROR, sizeof(err), &err);
229 		status = QDF_STATUS_E_INVAL;
230 		goto release_psoc_ref;
231 	}
232 
233 	status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp);
234 	if (QDF_IS_STATUS_ERROR(status))
235 		osif_err("ucfg_wifi_pos_process_req failed. status: %d",
236 			 status);
237 
238 release_psoc_ref:
239 	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
240 }
241 
242 static void os_if_wifi_pos_callback(const void *data, int data_len,
243 				    void *ctx, int pid)
244 {
245 	struct qdf_op_sync *op_sync;
246 
247 	if (qdf_op_protect(&op_sync))
248 		return;
249 
250 	__os_if_wifi_pos_callback(data, data_len, ctx, pid);
251 	qdf_op_unprotect(op_sync);
252 }
253 #else
254 static int __os_if_wifi_pos_callback(struct sk_buff *skb)
255 {
256 	uint8_t err;
257 	QDF_STATUS status;
258 	struct wifi_pos_req_msg req = {0};
259 	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
260 
261 	osif_debug("enter");
262 	if (!psoc) {
263 		osif_err("global psoc object not registered yet.");
264 		return -EINVAL;
265 	}
266 
267 	wlan_objmgr_psoc_get_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
268 	err = wifi_pos_parse_req(skb, &req);
269 	if (err) {
270 		os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc),
271 					ANI_MSG_OEM_ERROR, sizeof(err), &err);
272 		status = QDF_STATUS_E_INVAL;
273 		goto release_psoc_ref;
274 	}
275 
276 	status = ucfg_wifi_pos_process_req(psoc, &req, os_if_wifi_pos_send_rsp);
277 	if (QDF_IS_STATUS_ERROR(status))
278 		osif_err("ucfg_wifi_pos_process_req failed. status: %d",
279 			 status);
280 
281 release_psoc_ref:
282 	wlan_objmgr_psoc_release_ref(psoc, WLAN_WIFI_POS_OSIF_ID);
283 
284 	return qdf_status_to_os_return(status);
285 }
286 
287 static int os_if_wifi_pos_callback(struct sk_buff *skb)
288 {
289 	struct qdf_op_sync *op_sync;
290 	int err;
291 
292 	if (qdf_op_protect(&op_sync))
293 		return -EINVAL;
294 
295 	err = __os_if_wifi_pos_callback(skb);
296 	qdf_op_unprotect(op_sync);
297 
298 	return err;
299 }
300 #endif
301 
302 #ifdef CNSS_GENL
303 int os_if_wifi_pos_register_nl(void)
304 {
305 	int ret = register_cld_cmd_cb(WLAN_NL_MSG_OEM,
306 				os_if_wifi_pos_callback, NULL);
307 	if (ret)
308 		osif_err("register_cld_cmd_cb failed");
309 
310 	return ret;
311 }
312 #else
313 int os_if_wifi_pos_register_nl(void)
314 {
315 	return nl_srv_register(WLAN_NL_MSG_OEM, os_if_wifi_pos_callback);
316 }
317 #endif /* CNSS_GENL */
318 qdf_export_symbol(os_if_wifi_pos_register_nl);
319 
320 #ifdef CNSS_GENL
321 int os_if_wifi_pos_deregister_nl(void)
322 {
323 	int ret = deregister_cld_cmd_cb(WLAN_NL_MSG_OEM);
324 	if (ret)
325 		osif_err("deregister_cld_cmd_cb failed");
326 
327 	return ret;
328 }
329 #else
330 int os_if_wifi_pos_deregister_nl(void)
331 {
332 	return 0;
333 }
334 #endif /* CNSS_GENL */
335 
336 void os_if_wifi_pos_send_peer_status(struct qdf_mac_addr *peer_mac,
337 				uint8_t peer_status,
338 				uint8_t peer_timing_meas_cap,
339 				uint8_t session_id,
340 				struct wifi_pos_ch_info *chan_info,
341 				enum QDF_OPMODE dev_mode)
342 {
343 	struct wlan_objmgr_psoc *psoc = wifi_pos_get_psoc();
344 	struct wmi_pos_peer_status_info *peer_info;
345 
346 	if (!psoc) {
347 		osif_err("global wifi_pos psoc object not registered");
348 		return;
349 	}
350 
351 	if (!wifi_pos_is_app_registered(psoc) ||
352 			wifi_pos_get_app_pid(psoc) == 0) {
353 		osif_debug("app is not registered or pid is invalid");
354 		return;
355 	}
356 
357 	peer_info = qdf_mem_malloc(sizeof(*peer_info));
358 	if (!peer_info)
359 		return;
360 
361 	qdf_mem_copy(peer_info->peer_mac_addr, peer_mac->bytes,
362 		     sizeof(peer_mac->bytes));
363 	peer_info->peer_status = peer_status;
364 	peer_info->vdev_id = session_id;
365 	peer_info->peer_capability = peer_timing_meas_cap;
366 	peer_info->reserved0 = 0;
367 	/* Set 0th bit of reserved0 for STA mode */
368 	if (QDF_STA_MODE == dev_mode)
369 		peer_info->reserved0 |= 0x01;
370 
371 	if (chan_info) {
372 		peer_info->peer_chan_info.chan_id = chan_info->chan_id;
373 		peer_info->peer_chan_info.reserved0 = 0;
374 		peer_info->peer_chan_info.mhz = chan_info->mhz;
375 		peer_info->peer_chan_info.band_center_freq1 =
376 			chan_info->band_center_freq1;
377 		peer_info->peer_chan_info.band_center_freq2 =
378 			chan_info->band_center_freq2;
379 		peer_info->peer_chan_info.info = chan_info->info;
380 		peer_info->peer_chan_info.reg_info_1 = chan_info->reg_info_1;
381 		peer_info->peer_chan_info.reg_info_2 = chan_info->reg_info_2;
382 	}
383 
384 	os_if_wifi_pos_send_rsp(wifi_pos_get_app_pid(psoc),
385 				ANI_MSG_PEER_STATUS_IND,
386 				sizeof(*peer_info), (uint8_t *)peer_info);
387 	qdf_mem_free(peer_info);
388 }
389 
390 int os_if_wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
391 				   struct wifi_pos_driver_caps *caps)
392 {
393 	if (!psoc || !caps) {
394 		osif_err("psoc or caps buffer is null");
395 		return -EINVAL;
396 	}
397 
398 	return qdf_status_to_os_return(wifi_pos_populate_caps(psoc, caps));
399 }
400