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