xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/spectral/src/os_if_spectral_netlink.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2011, 2017-2021 The Linux Foundation. All rights reserved.
3  *
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <os_if_spectral_netlink.h>
21 #include <spectral_cmn_api_i.h>
22 #include <spectral_defs_i.h>
23 #include <wlan_nlink_srv.h>
24 #include <wlan_nlink_common.h>
25 #include <qdf_module.h>
26 #ifdef CNSS_GENL
27 #ifdef CONFIG_CNSS_OUT_OF_TREE
28 #include "cnss_nl.h"
29 #else
30 #include <net/cnss_nl.h>
31 #endif
32 #endif
33 #include <wlan_cfg80211.h>
34 
35 /**
36  * os_if_spectral_remove_nbuf_debug_entry() - Remove nbuf from nbuf debug table
37  * @nbuf - nbuf to remove from the nbuf debug table
38  *
39  * Remove nbuf from the nbuf debug hash table and decrement the nbuf count
40  *
41  * Return: None
42  */
43 static inline void os_if_spectral_remove_nbuf_debug_entry(qdf_nbuf_t nbuf)
44 {
45 	qdf_nbuf_count_dec(nbuf);
46 	qdf_net_buf_debug_release_skb(nbuf);
47 }
48 
49 #ifndef CNSS_GENL
50 static struct sock *os_if_spectral_nl_sock;
51 static atomic_t spectral_nl_users = ATOMIC_INIT(0);
52 #endif
53 
54 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
55 void
56 os_if_spectral_nl_data_ready(struct sock *sk, int len)
57 {
58 	spectral_debug("%d", __LINE__);
59 }
60 
61 #else
62 void
63 os_if_spectral_nl_data_ready(struct sk_buff *skb)
64 {
65 	spectral_debug("%d", __LINE__);
66 }
67 #endif				/* VERSION */
68 
69 #ifndef CNSS_GENL
70 /**
71  * os_if_spectral_init_nl_cfg() - Initialize netlink kernel
72  * configuration parameters
73  * @cfg : Pointer to netlink_kernel_cfg
74  *
75  * Initialize netlink kernel configuration parameters required
76  * for spectral module
77  *
78  * Return: None
79  */
80 #if KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE
81 static void
82 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg)
83 {
84 	cfg->groups = 1;
85 	cfg->input = os_if_spectral_nl_data_ready;
86 }
87 #else
88 static void
89 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg)
90 {
91 }
92 #endif
93 /**
94  * os_if_spectral_create_nl_sock() - Create Netlink socket
95  * @cfg : Pointer to netlink_kernel_cfg
96  *
97  * Create Netlink socket required for spectral module
98  *
99  * Return: None
100  */
101 #if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE
102 static void
103 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
104 {
105 	os_if_spectral_nl_sock =
106 	    (struct sock *)netlink_kernel_create(&init_net,
107 						 SPECTRAL_NETLINK, cfg);
108 }
109 #elif KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE
110 static void
111 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
112 {
113 	os_if_spectral_nl_sock =
114 	    (struct sock *)netlink_kernel_create(&init_net,
115 						 SPECTRAL_NETLINK,
116 						 THIS_MODULE, cfg);
117 }
118 #elif (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
119 static void
120 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
121 {
122 	os_if_spectral_nl_sock =
123 	    (struct sock *)netlink_kernel_create(
124 		SPECTRAL_NETLINK, 1,
125 		&os_if_spectral_nl_data_ready,
126 		THIS_MODULE);
127 }
128 #else
129 #if (KERNEL_VERSION(3, 10, 0) <= LINUX_VERSION_CODE)
130 static void
131 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
132 {
133 	memset(cfg, 0, sizeof(*cfg));
134 	cfg->groups = 1;
135 	cfg->input = &os_if_spectral_nl_data_ready;
136 	os_if_spectral_nl_sock =
137 	    (struct sock *)netlink_kernel_create(&init_net,
138 						 SPECTRAL_NETLINK, cfg);
139 }
140 #else
141 static void
142 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
143 {
144 	os_if_spectral_nl_sock =
145 	    (struct sock *)netlink_kernel_create(
146 		&init_net,
147 		SPECTRAL_NETLINK, 1,
148 		&os_if_spectral_nl_data_ready,
149 		NULL, THIS_MODULE);
150 }
151 #endif
152 #endif
153 
154 /**
155  * os_if_spectral_init_nl() - Initialize netlink data structures for
156  * spectral module
157  * @pdev : Pointer to pdev
158  *
159  * Return: 0 on success else failure
160  */
161 static int
162 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev)
163 {
164 	struct pdev_spectral *ps = NULL;
165 	struct netlink_kernel_cfg cfg;
166 
167 	memset(&cfg, 0, sizeof(cfg));
168 	if (!pdev) {
169 		osif_err("PDEV is NULL!");
170 		return -EINVAL;
171 	}
172 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
173 						   WLAN_UMAC_COMP_SPECTRAL);
174 
175 	if (!ps) {
176 		osif_err("PDEV SPECTRAL object is NULL!");
177 		return -EINVAL;
178 	}
179 	os_if_spectral_init_nl_cfg(&cfg);
180 
181 	if (!os_if_spectral_nl_sock) {
182 		os_if_spectral_create_nl_sock(&cfg);
183 
184 		if (!os_if_spectral_nl_sock) {
185 			osif_err("NETLINK_KERNEL_CREATE FAILED");
186 			return -ENODEV;
187 		}
188 	}
189 	ps->spectral_sock = os_if_spectral_nl_sock;
190 
191 	if (!ps->spectral_sock) {
192 		osif_err("ps->spectral_sock is NULL");
193 		return -ENODEV;
194 	}
195 	atomic_inc(&spectral_nl_users);
196 
197 	return 0;
198 }
199 
200 /**
201  * os_if_spectral_destroy_netlink() - De-initialize netlink data structures for
202  * spectral module
203  * @pdev : Pointer to pdev
204  *
205  * Return: Success/Failure
206  */
207 static int
208 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev)
209 {
210 	struct pdev_spectral *ps = NULL;
211 
212 	if (!pdev) {
213 		osif_err("PDEV is NULL!");
214 		return -EINVAL;
215 	}
216 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
217 						   WLAN_UMAC_COMP_SPECTRAL);
218 
219 	if (!ps) {
220 		osif_err("PDEV SPECTRAL object is NULL!");
221 		return -EINVAL;
222 	}
223 	ps->spectral_sock = NULL;
224 	if (atomic_dec_and_test(&spectral_nl_users)) {
225 		sock_release(os_if_spectral_nl_sock->sk_socket);
226 		os_if_spectral_nl_sock = NULL;
227 	}
228 	return 0;
229 }
230 #else
231 
232 static int
233 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev)
234 {
235 	return 0;
236 }
237 
238 static int
239 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev)
240 {
241 	return 0;
242 }
243 #endif
244 
245 void *
246 os_if_spectral_prep_skb(struct wlan_objmgr_pdev *pdev,
247 			enum spectral_msg_type smsg_type,
248 			enum spectral_msg_buf_type buf_type)
249 {
250 	struct pdev_spectral *ps = NULL;
251 	struct nlmsghdr *spectral_nlh = NULL;
252 	void *buf = NULL;
253 
254 	if (!pdev) {
255 		osif_err("PDEV is NULL!");
256 		return NULL;
257 	}
258 
259 	if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) {
260 		osif_err("Invalid Spectral message type %u", smsg_type);
261 		return NULL;
262 	}
263 
264 	if (buf_type >= SPECTRAL_MSG_BUF_TYPE_MAX) {
265 		osif_err("Invalid Spectral message buffer type %u",
266 			 buf_type);
267 		return NULL;
268 	}
269 
270 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
271 						   WLAN_UMAC_COMP_SPECTRAL);
272 
273 	if (!ps) {
274 		osif_err("PDEV SPECTRAL object is NULL!");
275 		return NULL;
276 	}
277 
278 	if (buf_type == SPECTRAL_MSG_BUF_NEW) {
279 		QDF_ASSERT(!ps->skb[smsg_type]);
280 		ps->skb[smsg_type] =
281 				qdf_nbuf_alloc(NULL, MAX_SPECTRAL_PAYLOAD,
282 					       0, 0, false);
283 
284 		if (!ps->skb[smsg_type]) {
285 			osif_err("alloc skb (len=%u, msg_type=%u) failed",
286 				 MAX_SPECTRAL_PAYLOAD, smsg_type);
287 			return NULL;
288 		}
289 
290 		qdf_nbuf_put_tail(ps->skb[smsg_type], MAX_SPECTRAL_PAYLOAD);
291 		spectral_nlh = (struct nlmsghdr *)ps->skb[smsg_type]->data;
292 
293 		qdf_mem_zero(spectral_nlh, sizeof(*spectral_nlh));
294 
295 		/*
296 		 * Possible bug that size of  struct spectral_samp_msg and
297 		 * SPECTRAL_MSG differ by 3 bytes  so we miss 3 bytes
298 		 */
299 
300 		spectral_nlh->nlmsg_len =
301 				NLMSG_SPACE(sizeof(struct spectral_samp_msg));
302 		spectral_nlh->nlmsg_pid = 0;
303 		spectral_nlh->nlmsg_flags = 0;
304 		spectral_nlh->nlmsg_type = WLAN_NL_MSG_SPECTRAL_SCAN;
305 
306 		qdf_mem_zero(NLMSG_DATA(spectral_nlh),
307 			     sizeof(struct spectral_samp_msg));
308 		buf = NLMSG_DATA(spectral_nlh);
309 	} else if (buf_type == SPECTRAL_MSG_BUF_SAVED) {
310 		QDF_ASSERT(ps->skb[smsg_type]);
311 		spectral_nlh = (struct nlmsghdr *)ps->skb[smsg_type]->data;
312 		buf = NLMSG_DATA(spectral_nlh);
313 	} else {
314 		osif_err("Failed to get spectral report buffer");
315 		buf = NULL;
316 	}
317 
318 	return buf;
319 }
320 
321 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
322 static inline void
323 os_if_init_spectral_skb_dst_pid(
324 	struct sk_buff *skb,
325 	struct pdev_spectral *ps)
326 {
327 	NETLINK_CB(skb).dst_pid =
328 	    ps->spectral_pid;
329 }
330 #else
331 static inline void
332 os_if_init_spectral_skb_dst_pid(
333 	struct sk_buff *skb,
334 	struct pdev_spectral *ps)
335 {
336 }
337 #endif			/* VERSION - field deprecated by newer kernels */
338 
339 #if KERNEL_VERSION(3, 7, 0) > LINUX_VERSION_CODE
340 static inline void
341 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb)
342 {
343 	NETLINK_CB(skb).pid = 0;  /* from kernel */
344 }
345 #else
346 static inline void
347 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb)
348 {
349 	NETLINK_CB(skb).portid = 0;  /* from kernel */
350 }
351 #endif
352 
353 
354 /**
355  * os_if_spectral_nl_unicast_msg() - Sends unicast Spectral message to user
356  * space
357  * @pdev : Pointer to pdev
358  * @smsg_type: Spectral message type
359  *
360  * Return: void
361  */
362 #ifndef CNSS_GENL
363 static int
364 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev,
365 			      enum spectral_msg_type smsg_type)
366 {
367 	struct pdev_spectral *ps = NULL;
368 	int status;
369 
370 	if (!pdev) {
371 		osif_err("PDEV is NULL!");
372 		return -EINVAL;
373 	}
374 
375 	if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) {
376 		osif_err("Invalid Spectral message type %u", smsg_type);
377 		return -EINVAL;
378 	}
379 
380 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
381 						   WLAN_UMAC_COMP_SPECTRAL);
382 	if (!ps) {
383 		osif_err("PDEV SPECTRAL object is NULL!");
384 		return -EINVAL;
385 	}
386 
387 	if (!ps->skb[smsg_type]) {
388 		osif_err("Socket buffer is null, msg_type= %u", smsg_type);
389 		return -EINVAL;
390 	}
391 
392 	if (!ps->spectral_sock) {
393 		osif_err("Spectral Socket is invalid, msg_type= %u",
394 			 smsg_type);
395 		qdf_nbuf_free(ps->skb[smsg_type]);
396 		ps->skb[smsg_type] = NULL;
397 
398 		return -EINVAL;
399 	}
400 
401 	os_if_init_spectral_skb_dst_pid(ps->skb[smsg_type], ps);
402 
403 	os_if_init_spectral_skb_pid_portid(ps->skb[smsg_type]);
404 
405 	/* to mcast group 1<<0 */
406 	NETLINK_CB(ps->skb[smsg_type]).dst_group = 0;
407 
408 	os_if_spectral_remove_nbuf_debug_entry(ps->skb[smsg_type]);
409 	status = netlink_unicast(ps->spectral_sock,
410 				 ps->skb[smsg_type],
411 				 ps->spectral_pid, MSG_DONTWAIT);
412 
413 	/* clear the local copy, free would be done by netlink layer */
414 	ps->skb[smsg_type] = NULL;
415 
416 	return status;
417 }
418 #else
419 
420 static int
421 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev,
422 			      enum spectral_msg_type smsg_type)
423 {
424 	struct pdev_spectral *ps = NULL;
425 	int status;
426 
427 	if (!pdev) {
428 		osif_err("PDEV is NULL!");
429 		return -EINVAL;
430 	}
431 
432 	if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) {
433 		osif_err("Invalid Spectral message type %u", smsg_type);
434 		return -EINVAL;
435 	}
436 
437 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
438 						   WLAN_UMAC_COMP_SPECTRAL);
439 	if (!ps) {
440 		osif_err("PDEV SPECTRAL object is NULL!");
441 		return -EINVAL;
442 	}
443 
444 	if (!ps->skb[smsg_type]) {
445 		osif_err("Socket buffer is null, msg_type= %u", smsg_type);
446 		return -EINVAL;
447 	}
448 
449 	os_if_init_spectral_skb_pid_portid(ps->skb[smsg_type]);
450 
451 	os_if_spectral_remove_nbuf_debug_entry(ps->skb[smsg_type]);
452 	status = nl_srv_ucast(ps->skb[smsg_type], ps->spectral_pid,
453 			      MSG_DONTWAIT, WLAN_NL_MSG_SPECTRAL_SCAN,
454 			      CLD80211_MCGRP_OEM_MSGS);
455 	if (status < 0)
456 		osif_err("failed to send to spectral scan app");
457 
458 	/* clear the local copy, free would be done by netlink layer */
459 	ps->skb[smsg_type] = NULL;
460 
461 	return status;
462 }
463 
464 #endif
465 
466 /**
467  * os_if_spectral_nl_bcast_msg() - Sends broadcast Spectral message to user
468  * space
469  * @pdev : Pointer to pdev
470  * @smsg_type: Spectral message type
471  *
472  * Return: void
473  */
474 static int
475 os_if_spectral_nl_bcast_msg(struct wlan_objmgr_pdev *pdev,
476 			    enum spectral_msg_type smsg_type)
477 {
478 #if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE)
479 	fd_set write_set;
480 #endif
481 	int status;
482 	struct pdev_spectral *ps = NULL;
483 
484 #if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE)
485 	FD_ZERO(&write_set);
486 #endif
487 
488 	if (!pdev) {
489 		osif_err("PDEV is NULL!");
490 		return -EINVAL;
491 	}
492 
493 	if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) {
494 		osif_err("Invalid Spectral message type %u", smsg_type);
495 		return -EINVAL;
496 	}
497 
498 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
499 						   WLAN_UMAC_COMP_SPECTRAL);
500 
501 	if (!ps) {
502 		osif_err("PDEV SPECTRAL object is NULL!");
503 		return -EINVAL;
504 	}
505 
506 	if (!ps->skb[smsg_type]) {
507 		osif_err("Socket buffer is null, msg_type= %u", smsg_type);
508 		return -EINVAL;
509 	}
510 
511 	if (!ps->spectral_sock) {
512 		qdf_nbuf_free(ps->skb[smsg_type]);
513 		ps->skb[smsg_type] = NULL;
514 
515 		return -EINVAL;
516 	}
517 
518 	os_if_spectral_remove_nbuf_debug_entry(ps->skb[smsg_type]);
519 	status = netlink_broadcast(ps->spectral_sock,
520 				   ps->skb[smsg_type],
521 				   0, 1, GFP_ATOMIC);
522 
523 	/* clear the local copy, free would be done by netlink layer */
524 	ps->skb[smsg_type] = NULL;
525 
526 	return status;
527 }
528 
529 /**
530  * os_if_spectral_free_skb() - Free spectral SAMP message skb
531  *
532  * @pdev : Pointer to pdev
533  * @smsg_type: Spectral message type
534  *
535  * Return: void
536  */
537 static void
538 os_if_spectral_free_skb(struct wlan_objmgr_pdev *pdev,
539 			enum spectral_msg_type smsg_type)
540 {
541 	struct pdev_spectral *ps = NULL;
542 
543 	if (!pdev) {
544 		osif_err("PDEV is NULL!");
545 		return;
546 	}
547 
548 	if (smsg_type >= SPECTRAL_MSG_TYPE_MAX) {
549 		osif_err("Invalid Spectral message type %u", smsg_type);
550 		return;
551 	}
552 
553 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
554 						   WLAN_UMAC_COMP_SPECTRAL);
555 
556 	if (!ps) {
557 		osif_err("PDEV SPECTRAL object is NULL!");
558 		return;
559 	}
560 
561 	if (!ps->skb[smsg_type]) {
562 		osif_info("Socket buffer is null, msg_type= %u", smsg_type);
563 		return;
564 	}
565 
566 	/* Free buffer */
567 	qdf_nbuf_free(ps->skb[smsg_type]);
568 
569 	/* clear the local copy */
570 	ps->skb[smsg_type] = NULL;
571 }
572 
573 void
574 os_if_spectral_netlink_init(struct wlan_objmgr_pdev *pdev)
575 {
576 	struct spectral_nl_cb nl_cb = {0};
577 	struct spectral_context *sptrl_ctx;
578 
579 	if (!pdev) {
580 		osif_err("PDEV is NULL!");
581 		return;
582 	}
583 
584 	if (wlan_spectral_is_feature_disabled_pdev(pdev)) {
585 		osif_err("Spectral feature is disabled");
586 		return;
587 	}
588 
589 	sptrl_ctx = spectral_get_spectral_ctx_from_pdev(pdev);
590 
591 	if (!sptrl_ctx) {
592 		osif_err("Spectral context is NULL!");
593 		return;
594 	}
595 
596 	os_if_spectral_init_nl(pdev);
597 
598 	/* Register Netlink handlers */
599 	nl_cb.get_sbuff = os_if_spectral_prep_skb;
600 	nl_cb.send_nl_bcast = os_if_spectral_nl_bcast_msg;
601 	nl_cb.send_nl_unicast = os_if_spectral_nl_unicast_msg;
602 	nl_cb.free_sbuff = os_if_spectral_free_skb;
603 
604 	if (sptrl_ctx->sptrlc_register_netlink_cb)
605 		sptrl_ctx->sptrlc_register_netlink_cb(pdev, &nl_cb);
606 }
607 qdf_export_symbol(os_if_spectral_netlink_init);
608 
609 void os_if_spectral_netlink_deinit(struct wlan_objmgr_pdev *pdev)
610 {
611 	struct spectral_context *sptrl_ctx;
612 	enum spectral_msg_type msg_type = SPECTRAL_MSG_NORMAL_MODE;
613 
614 	if (!pdev) {
615 		osif_err("PDEV is NULL!");
616 		return;
617 	}
618 
619 	if (wlan_spectral_is_feature_disabled_pdev(pdev)) {
620 		osif_err("Spectral feature is disabled");
621 		return;
622 	}
623 
624 	sptrl_ctx = spectral_get_spectral_ctx_from_pdev(pdev);
625 
626 	if (!sptrl_ctx) {
627 		osif_err("Spectral context is NULL!");
628 		return;
629 	}
630 
631 	for (; msg_type < SPECTRAL_MSG_TYPE_MAX; msg_type++)
632 		os_if_spectral_free_skb(pdev, msg_type);
633 
634 	if (sptrl_ctx->sptrlc_deregister_netlink_cb)
635 		sptrl_ctx->sptrlc_deregister_netlink_cb(pdev);
636 
637 	os_if_spectral_destroy_netlink(pdev);
638 }
639 qdf_export_symbol(os_if_spectral_netlink_deinit);
640