xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/spectral/src/os_if_spectral_netlink.c (revision a175314c51a4ce5cec2835cc8a8c7dc0c1810915)
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 #ifndef CNSS_GENL
31 static struct sock *os_if_spectral_nl_sock;
32 static atomic_t spectral_nl_users = ATOMIC_INIT(0);
33 #endif
34 
35 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
36 void
37 os_if_spectral_nl_data_ready(struct sock *sk, int len)
38 {
39 	spectral_debug("%d", __LINE__);
40 }
41 
42 #else
43 void
44 os_if_spectral_nl_data_ready(struct sk_buff *skb)
45 {
46 	spectral_debug("%d", __LINE__);
47 }
48 #endif				/* VERSION */
49 
50 #ifndef CNSS_GENL
51 /**
52  * os_if_spectral_init_nl_cfg() - Initialize netlink kernel
53  * configuration parameters
54  * @cfg : Pointer to netlink_kernel_cfg
55  *
56  * Initialize netlink kernel configuration parameters required
57  * for spectral module
58  *
59  * Return: None
60  */
61 #if KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE
62 static void
63 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg)
64 {
65 	cfg->groups = 1;
66 	cfg->input = os_if_spectral_nl_data_ready;
67 }
68 #else
69 static void
70 os_if_spectral_init_nl_cfg(struct netlink_kernel_cfg *cfg)
71 {
72 }
73 #endif
74 /**
75  * os_if_spectral_create_nl_sock() - Create Netlink socket
76  * @cfg : Pointer to netlink_kernel_cfg
77  *
78  * Create Netlink socket required for spectral module
79  *
80  * Return: None
81  */
82 #if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE
83 static void
84 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
85 {
86 	os_if_spectral_nl_sock =
87 	    (struct sock *)netlink_kernel_create(&init_net,
88 						 SPECTRAL_NETLINK, cfg);
89 }
90 #elif KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE
91 static void
92 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
93 {
94 	os_if_spectral_nl_sock =
95 	    (struct sock *)netlink_kernel_create(&init_net,
96 						 SPECTRAL_NETLINK,
97 						 THIS_MODULE, cfg);
98 }
99 #elif (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
100 static void
101 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
102 {
103 	os_if_spectral_nl_sock =
104 	    (struct sock *)netlink_kernel_create(
105 		SPECTRAL_NETLINK, 1,
106 		&os_if_spectral_nl_data_ready,
107 		THIS_MODULE);
108 }
109 #else
110 #if (KERNEL_VERSION(3, 10, 0) <= LINUX_VERSION_CODE)
111 static void
112 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
113 {
114 	memset(cfg, 0, sizeof(*cfg));
115 	cfg->groups = 1;
116 	cfg->input = &os_if_spectral_nl_data_ready;
117 	os_if_spectral_nl_sock =
118 	    (struct sock *)netlink_kernel_create(&init_net,
119 						 SPECTRAL_NETLINK, cfg);
120 }
121 #else
122 static void
123 os_if_spectral_create_nl_sock(struct netlink_kernel_cfg *cfg)
124 {
125 	os_if_spectral_nl_sock =
126 	    (struct sock *)netlink_kernel_create(
127 		&init_net,
128 		SPECTRAL_NETLINK, 1,
129 		&os_if_spectral_nl_data_ready,
130 		NULL, THIS_MODULE);
131 }
132 #endif
133 #endif
134 
135 /**
136  * os_if_spectral_init_nl() - Initialize netlink data structures for
137  * spectral module
138  * @pdev : Pointer to pdev
139  *
140  * Return: 0 on success else failure
141  */
142 static int
143 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev)
144 {
145 	struct pdev_spectral *ps = NULL;
146 	struct netlink_kernel_cfg cfg;
147 
148 	memset(&cfg, 0, sizeof(cfg));
149 	if (!pdev) {
150 		spectral_err("PDEV is NULL!");
151 		return -EINVAL;
152 	}
153 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
154 						   WLAN_UMAC_COMP_SPECTRAL);
155 
156 	if (!ps) {
157 		spectral_err("PDEV SPECTRAL object is NULL!");
158 		return -EINVAL;
159 	}
160 	os_if_spectral_init_nl_cfg(&cfg);
161 
162 	if (!os_if_spectral_nl_sock) {
163 		os_if_spectral_create_nl_sock(&cfg);
164 
165 		if (!os_if_spectral_nl_sock) {
166 			spectral_err("NETLINK_KERNEL_CREATE FAILED");
167 			return -ENODEV;
168 		}
169 	}
170 	ps->spectral_sock = os_if_spectral_nl_sock;
171 
172 	if (!ps->spectral_sock) {
173 		spectral_err("ps->spectral_sock is NULL");
174 		return -ENODEV;
175 	}
176 	atomic_inc(&spectral_nl_users);
177 
178 	return 0;
179 }
180 
181 /**
182  * os_if_spectral_destroy_netlink() - De-initialize netlink data structures for
183  * spectral module
184  * @pdev : Pointer to pdev
185  *
186  * Return: Success/Failure
187  */
188 static int
189 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev)
190 {
191 	struct pdev_spectral *ps = NULL;
192 
193 	if (!pdev) {
194 		spectral_err("PDEV is NULL!");
195 		return -EINVAL;
196 	}
197 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
198 						   WLAN_UMAC_COMP_SPECTRAL);
199 
200 	if (!ps) {
201 		spectral_err("PDEV SPECTRAL object is NULL!");
202 		return -EINVAL;
203 	}
204 	ps->spectral_sock = NULL;
205 	if (atomic_dec_and_test(&spectral_nl_users)) {
206 		sock_release(os_if_spectral_nl_sock->sk_socket);
207 		os_if_spectral_nl_sock = NULL;
208 	}
209 	return 0;
210 }
211 #else
212 
213 static int
214 os_if_spectral_init_nl(struct wlan_objmgr_pdev *pdev)
215 {
216 	return 0;
217 }
218 
219 static int
220 os_if_spectral_destroy_netlink(struct wlan_objmgr_pdev *pdev)
221 {
222 	return 0;
223 }
224 #endif
225 
226 void *
227 os_if_spectral_prep_skb(struct wlan_objmgr_pdev *pdev)
228 {
229 	struct pdev_spectral *ps = NULL;
230 	struct nlmsghdr *spectral_nlh = NULL;
231 
232 	if (!pdev) {
233 		spectral_err("PDEV is NULL!");
234 		return NULL;
235 	}
236 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
237 						   WLAN_UMAC_COMP_SPECTRAL);
238 
239 	if (!ps) {
240 		spectral_err("PDEV SPECTRAL object is NULL!");
241 		return NULL;
242 	}
243 	ps->skb = qdf_nbuf_alloc(NULL, MAX_SPECTRAL_PAYLOAD, 0, 0, false);
244 
245 	if (!ps->skb) {
246 		spectral_err("allocate skb (len=%u) failed",
247 			     MAX_SPECTRAL_PAYLOAD);
248 		return NULL;
249 	}
250 
251 	qdf_nbuf_put_tail(ps->skb, MAX_SPECTRAL_PAYLOAD);
252 	spectral_nlh = (struct nlmsghdr *)ps->skb->data;
253 
254 	OS_MEMZERO(spectral_nlh, sizeof(*spectral_nlh));
255 
256 	/*
257 	 * Possible bug that size of  struct spectral_samp_msg and
258 	 * SPECTRAL_MSG differ by 3 bytes  so we miss 3 bytes
259 	 */
260 
261 	spectral_nlh->nlmsg_len = NLMSG_SPACE(sizeof(struct spectral_samp_msg));
262 	spectral_nlh->nlmsg_pid = 0;
263 	spectral_nlh->nlmsg_flags = 0;
264 	spectral_nlh->nlmsg_type = WLAN_NL_MSG_SPECTRAL_SCAN;
265 
266 	return NLMSG_DATA(spectral_nlh);
267 }
268 
269 #if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
270 static inline void
271 os_if_init_spectral_skb_dst_pid(
272 	struct sk_buff *skb,
273 	struct pdev_spectral *ps)
274 {
275 	NETLINK_CB(skb).dst_pid =
276 	    ps->spectral_pid;
277 }
278 #else
279 static inline void
280 os_if_init_spectral_skb_dst_pid(
281 	struct sk_buff *skb,
282 	struct pdev_spectral *ps)
283 {
284 }
285 #endif			/* VERSION - field deprecated by newer kernels */
286 
287 #if KERNEL_VERSION(3, 7, 0) > LINUX_VERSION_CODE
288 static inline void
289 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb)
290 {
291 	NETLINK_CB(skb).pid = 0;  /* from kernel */
292 }
293 #else
294 static inline void
295 os_if_init_spectral_skb_pid_portid(struct sk_buff *skb)
296 {
297 	NETLINK_CB(skb).portid = 0;  /* from kernel */
298 }
299 #endif
300 
301 
302 /**
303  * os_if_spectral_nl_unicast_msg() - Sends unicast Spectral message to user
304  * space
305  * @pdev : Pointer to pdev
306  *
307  * Return: void
308  */
309 #ifndef CNSS_GENL
310 static int
311 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev)
312 {
313 	struct pdev_spectral *ps = NULL;
314 	int status;
315 
316 	if (!pdev) {
317 		spectral_err("PDEV is NULL!");
318 		return -EINVAL;
319 	}
320 
321 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
322 						   WLAN_UMAC_COMP_SPECTRAL);
323 	if (!ps) {
324 		spectral_err("PDEV SPECTRAL object is NULL!");
325 		return -EINVAL;
326 	}
327 
328 	if (!ps->skb) {
329 		spectral_err("Socket buffer is null");
330 		return -EINVAL;
331 	}
332 
333 	if (!ps->spectral_sock) {
334 		spectral_err("Spectral Socket is invalid");
335 		dev_kfree_skb(ps->skb);
336 		return -EINVAL;
337 	}
338 
339 	os_if_init_spectral_skb_dst_pid(ps->skb, ps);
340 
341 	os_if_init_spectral_skb_pid_portid(ps->skb);
342 
343 	/* to mcast group 1<<0 */
344 	NETLINK_CB(ps->skb).dst_group = 0;
345 
346 	status = netlink_unicast(ps->spectral_sock,
347 				 ps->skb,
348 				 ps->spectral_pid, MSG_DONTWAIT);
349 
350 	return status;
351 }
352 #else
353 
354 static int
355 os_if_spectral_nl_unicast_msg(struct wlan_objmgr_pdev *pdev)
356 {
357 	struct pdev_spectral *ps = NULL;
358 	int status;
359 
360 	if (!pdev) {
361 		spectral_err("PDEV is NULL!");
362 		return -EINVAL;
363 	}
364 
365 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
366 						   WLAN_UMAC_COMP_SPECTRAL);
367 	if (!ps) {
368 		spectral_err("PDEV SPECTRAL object is NULL!");
369 		return -EINVAL;
370 	}
371 
372 	if (!ps->skb) {
373 		spectral_err("Socket buffer is null");
374 		return -EINVAL;
375 	}
376 
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 qdf_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 qdf_export_symbol(os_if_spectral_netlink_deinit);
489