xref: /wlan-driver/qca-wifi-host-cmn/utils/ptt/src/wlan_ptt_sock_svc.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /******************************************************************************
21*5113495bSYour Name * wlan_ptt_sock_svc.c
22*5113495bSYour Name *
23*5113495bSYour Name ******************************************************************************/
24*5113495bSYour Name #ifdef PTT_SOCK_SVC_ENABLE
25*5113495bSYour Name #include <wlan_nlink_srv.h>
26*5113495bSYour Name #include <qdf_types.h>
27*5113495bSYour Name #include <qdf_status.h>
28*5113495bSYour Name #include <qdf_trace.h>
29*5113495bSYour Name #include <wlan_nlink_common.h>
30*5113495bSYour Name #include <wlan_ptt_sock_svc.h>
31*5113495bSYour Name #include <qdf_types.h>
32*5113495bSYour Name #include <qdf_trace.h>
33*5113495bSYour Name 
34*5113495bSYour Name #ifdef CNSS_GENL
35*5113495bSYour Name #ifdef CONFIG_CNSS_OUT_OF_TREE
36*5113495bSYour Name #include "cnss_nl.h"
37*5113495bSYour Name #else
38*5113495bSYour Name #include <net/cnss_nl.h>
39*5113495bSYour Name #endif
40*5113495bSYour Name #include <wlan_cfg80211.h>
41*5113495bSYour Name #endif
42*5113495bSYour Name 
43*5113495bSYour Name #define PTT_SOCK_DEBUG
44*5113495bSYour Name #ifdef PTT_SOCK_DEBUG
45*5113495bSYour Name #define PTT_TRACE(level, args ...) QDF_TRACE(QDF_MODULE_ID_QDF, level, ## args)
46*5113495bSYour Name #else
47*5113495bSYour Name #define PTT_TRACE(level, args ...)
48*5113495bSYour Name #endif
49*5113495bSYour Name 
50*5113495bSYour Name #ifdef PTT_SOCK_DEBUG_VERBOSE
51*5113495bSYour Name /* Utility function to perform a hex dump */
ptt_sock_dump_buf(const unsigned char * pbuf,int cnt)52*5113495bSYour Name static void ptt_sock_dump_buf(const unsigned char *pbuf, int cnt)
53*5113495bSYour Name {
54*5113495bSYour Name 	int i;
55*5113495bSYour Name 
56*5113495bSYour Name 	for (i = 0; i < cnt; i++) {
57*5113495bSYour Name 		if ((i % 16) == 0)
58*5113495bSYour Name 			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
59*5113495bSYour Name 				  "\n%pK:", pbuf);
60*5113495bSYour Name 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, " %02X",
61*5113495bSYour Name 			  *pbuf);
62*5113495bSYour Name 		pbuf++;
63*5113495bSYour Name 	}
64*5113495bSYour Name 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, "\n");
65*5113495bSYour Name }
66*5113495bSYour Name #endif
67*5113495bSYour Name 
68*5113495bSYour Name /**
69*5113495bSYour Name  * nl_srv_ucast_ptt() - Wrapper function to send ucast msgs to PTT
70*5113495bSYour Name  * @skb: sk buffer pointer
71*5113495bSYour Name  * @dst_pid: Destination PID
72*5113495bSYour Name  * @flag: flags
73*5113495bSYour Name  *
74*5113495bSYour Name  * Sends the ucast message to PTT with generic nl socket if CNSS_GENL
75*5113495bSYour Name  * is enabled. Else, use the legacy netlink socket to send.
76*5113495bSYour Name  *
77*5113495bSYour Name  * Return: zero on success, error code otherwise
78*5113495bSYour Name  */
nl_srv_ucast_ptt(struct sk_buff * skb,int dst_pid,int flag)79*5113495bSYour Name static int nl_srv_ucast_ptt(struct sk_buff *skb, int dst_pid, int flag)
80*5113495bSYour Name {
81*5113495bSYour Name #ifdef CNSS_GENL
82*5113495bSYour Name 	return nl_srv_ucast(skb, dst_pid, flag, ANI_NL_MSG_PUMAC,
83*5113495bSYour Name 				CLD80211_MCGRP_DIAG_EVENTS);
84*5113495bSYour Name #else
85*5113495bSYour Name 	return nl_srv_ucast(skb, dst_pid, flag);
86*5113495bSYour Name #endif
87*5113495bSYour Name }
88*5113495bSYour Name 
89*5113495bSYour Name /**
90*5113495bSYour Name  * nl_srv_bcast_ptt() - Wrapper function to send bcast msgs to DIAG mcast group
91*5113495bSYour Name  * @skb: sk buffer pointer
92*5113495bSYour Name  *
93*5113495bSYour Name  * Sends the bcast message to DIAG multicast group with generic nl socket
94*5113495bSYour Name  * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
95*5113495bSYour Name  *
96*5113495bSYour Name  * Return: zero on success, error code otherwise
97*5113495bSYour Name  */
nl_srv_bcast_ptt(struct sk_buff * skb)98*5113495bSYour Name static int nl_srv_bcast_ptt(struct sk_buff *skb)
99*5113495bSYour Name {
100*5113495bSYour Name #ifdef CNSS_GENL
101*5113495bSYour Name 	return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC);
102*5113495bSYour Name #else
103*5113495bSYour Name 	return nl_srv_bcast(skb);
104*5113495bSYour Name #endif
105*5113495bSYour Name }
106*5113495bSYour Name 
107*5113495bSYour Name /**
108*5113495bSYour Name  * ptt_sock_send_msg_to_app() - Send nl message to user space
109*5113495bSYour Name  * wmsg: Message header
110*5113495bSYour Name  * radio: Unit number of the radio
111*5113495bSYour Name  * src_mod: Message type
112*5113495bSYour Name  * pid: Process ID to which message will be unicast. Message
113*5113495bSYour Name  * will be broadcast when PID is INVALID_PID
114*5113495bSYour Name  *
115*5113495bSYour Name  * Utility function to send a netlink message to an application in user space
116*5113495bSYour Name  *
117*5113495bSYour Name  * Return: 0 on success and negative value on failure
118*5113495bSYour Name  */
ptt_sock_send_msg_to_app(tAniHdr * wmsg,int radio,int src_mod,int pid)119*5113495bSYour Name int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid)
120*5113495bSYour Name {
121*5113495bSYour Name 	int err = -1;
122*5113495bSYour Name 	int payload_len;
123*5113495bSYour Name 	int tot_msg_len;
124*5113495bSYour Name 	tAniNlHdr *wnl;
125*5113495bSYour Name 	struct sk_buff *skb;
126*5113495bSYour Name 	struct nlmsghdr *nlh;
127*5113495bSYour Name 	int wmsg_length = be16_to_cpu(wmsg->length);
128*5113495bSYour Name 	static int nlmsg_seq;
129*5113495bSYour Name 
130*5113495bSYour Name 	if (radio < 0 || radio > ANI_MAX_RADIOS) {
131*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s: invalid radio id [%d]\n",
132*5113495bSYour Name 			  __func__, radio);
133*5113495bSYour Name 		return -EINVAL;
134*5113495bSYour Name 	}
135*5113495bSYour Name 	payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(*wmsg);
136*5113495bSYour Name 	tot_msg_len = NLMSG_SPACE(payload_len);
137*5113495bSYour Name 	skb = dev_alloc_skb(tot_msg_len);
138*5113495bSYour Name 	if (!skb) {
139*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
140*5113495bSYour Name 			  "%s: dev_alloc_skb() failed for msg size[%d]\n",
141*5113495bSYour Name 			  __func__, tot_msg_len);
142*5113495bSYour Name 		return -ENOMEM;
143*5113495bSYour Name 	}
144*5113495bSYour Name 	nlh =
145*5113495bSYour Name 		nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len,
146*5113495bSYour Name 			  NLM_F_REQUEST);
147*5113495bSYour Name 	if (!nlh) {
148*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
149*5113495bSYour Name 			  "%s: nlmsg_put() failed for msg size[%d]\n", __func__,
150*5113495bSYour Name 			  tot_msg_len);
151*5113495bSYour Name 		kfree_skb(skb);
152*5113495bSYour Name 		return -ENOMEM;
153*5113495bSYour Name 	}
154*5113495bSYour Name 	wnl = (tAniNlHdr *) nlh;
155*5113495bSYour Name 	wnl->radio = radio;
156*5113495bSYour Name 
157*5113495bSYour Name 	/* Offset of data buffer from nlmsg_hdr + sizeof(int) radio */
158*5113495bSYour Name 	memcpy(nlmsg_data(nlh) + sizeof(wnl->radio), wmsg, wmsg_length);
159*5113495bSYour Name #ifdef PTT_SOCK_DEBUG_VERBOSE
160*5113495bSYour Name 	ptt_sock_dump_buf((const unsigned char *)skb->data, skb->len);
161*5113495bSYour Name #endif
162*5113495bSYour Name 
163*5113495bSYour Name 	if (pid != INVALID_PID)
164*5113495bSYour Name 		err = nl_srv_ucast_ptt(skb, pid, MSG_DONTWAIT);
165*5113495bSYour Name 	else
166*5113495bSYour Name 		err = nl_srv_bcast_ptt(skb);
167*5113495bSYour Name 
168*5113495bSYour Name 	if ((err < 0) && (err != -ESRCH))
169*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_INFO,
170*5113495bSYour Name 			  "%s:Failed sending Msg Type [0x%X] to pid[%d]\n",
171*5113495bSYour Name 			  __func__, be16_to_cpu(wmsg->type), pid);
172*5113495bSYour Name 	return err;
173*5113495bSYour Name }
174*5113495bSYour Name 
175*5113495bSYour Name #ifdef CNSS_GENL
176*5113495bSYour Name /**
177*5113495bSYour Name  * ptt_cmd_handler() - Handler function for PTT commands
178*5113495bSYour Name  * @data: Data to be parsed
179*5113495bSYour Name  * @data_len: Length of the data received
180*5113495bSYour Name  * @ctx: Registered context reference
181*5113495bSYour Name  * @pid: Process id of the user space application
182*5113495bSYour Name  *
183*5113495bSYour Name  * This function handles the command from PTT user space application
184*5113495bSYour Name  *
185*5113495bSYour Name  * Return: None
186*5113495bSYour Name  */
ptt_cmd_handler(const void * data,int data_len,void * ctx,int pid)187*5113495bSYour Name static void ptt_cmd_handler(const void *data, int data_len, void *ctx, int pid)
188*5113495bSYour Name {
189*5113495bSYour Name 	uint16_t length;
190*5113495bSYour Name 	struct sptt_app_reg_req *payload;
191*5113495bSYour Name 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
192*5113495bSYour Name 
193*5113495bSYour Name 	/*
194*5113495bSYour Name 	 * audit note: it is ok to pass a NULL policy here since a
195*5113495bSYour Name 	 * length check on the data is added later already
196*5113495bSYour Name 	 */
197*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX,
198*5113495bSYour Name 				    data, data_len, NULL)) {
199*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "Invalid ATTR");
200*5113495bSYour Name 		return;
201*5113495bSYour Name 	}
202*5113495bSYour Name 
203*5113495bSYour Name 	if (!tb[CLD80211_ATTR_DATA]) {
204*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "attr ATTR_DATA failed");
205*5113495bSYour Name 		return;
206*5113495bSYour Name 	}
207*5113495bSYour Name 
208*5113495bSYour Name 	if (nla_len(tb[CLD80211_ATTR_DATA]) < sizeof(struct sptt_app_reg_req)) {
209*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s:attr length check fails\n",
210*5113495bSYour Name 			__func__);
211*5113495bSYour Name 		return;
212*5113495bSYour Name 	}
213*5113495bSYour Name 
214*5113495bSYour Name 	payload = (struct sptt_app_reg_req *)(nla_data(tb[CLD80211_ATTR_DATA]));
215*5113495bSYour Name 	length = be16_to_cpu(payload->wmsg.length);
216*5113495bSYour Name 	if ((USHRT_MAX - length) < (sizeof(payload->radio) + sizeof(tAniHdr))) {
217*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
218*5113495bSYour Name 			"u16 overflow length %d %zu %zu",
219*5113495bSYour Name 			length,
220*5113495bSYour Name 			sizeof(payload->radio),
221*5113495bSYour Name 			sizeof(tAniHdr));
222*5113495bSYour Name 		return;
223*5113495bSYour Name 	}
224*5113495bSYour Name 
225*5113495bSYour Name 	if (nla_len(tb[CLD80211_ATTR_DATA]) <  (length +
226*5113495bSYour Name 						sizeof(payload->radio) +
227*5113495bSYour Name 						sizeof(tAniHdr))) {
228*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "ATTR_DATA len check failed");
229*5113495bSYour Name 		return;
230*5113495bSYour Name 	}
231*5113495bSYour Name 
232*5113495bSYour Name 	switch (payload->wmsg.type) {
233*5113495bSYour Name 	case ANI_MSG_APP_REG_REQ:
234*5113495bSYour Name 		ptt_sock_send_msg_to_app(&payload->wmsg, payload->radio,
235*5113495bSYour Name 							ANI_NL_MSG_PUMAC, pid);
236*5113495bSYour Name 		break;
237*5113495bSYour Name 	default:
238*5113495bSYour Name 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "Unknown msg type %d",
239*5113495bSYour Name 							payload->wmsg.type);
240*5113495bSYour Name 		break;
241*5113495bSYour Name 	}
242*5113495bSYour Name }
243*5113495bSYour Name 
ptt_sock_activate_svc(void)244*5113495bSYour Name void ptt_sock_activate_svc(void)
245*5113495bSYour Name {
246*5113495bSYour Name 	register_cld_cmd_cb(ANI_NL_MSG_PUMAC, ptt_cmd_handler, NULL);
247*5113495bSYour Name 	register_cld_cmd_cb(ANI_NL_MSG_PTT, ptt_cmd_handler, NULL);
248*5113495bSYour Name }
249*5113495bSYour Name 
ptt_sock_deactivate_svc(void)250*5113495bSYour Name void ptt_sock_deactivate_svc(void)
251*5113495bSYour Name {
252*5113495bSYour Name 	deregister_cld_cmd_cb(ANI_NL_MSG_PTT);
253*5113495bSYour Name 	deregister_cld_cmd_cb(ANI_NL_MSG_PUMAC);
254*5113495bSYour Name }
255*5113495bSYour Name #endif
256*5113495bSYour Name #endif /* PTT_SOCK_SVC_ENABLE */
257