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