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