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