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