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