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