xref: /wlan-dirver/qca-wifi-host-cmn/utils/ptt/src/wlan_ptt_sock_svc.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2012-2017 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 #else
37 
38 /** ptt Process ID */
39 static int32_t ptt_pid = INVALID_PID;
40 #endif
41 
42 #define PTT_SOCK_DEBUG
43 #ifdef PTT_SOCK_DEBUG
44 #define PTT_TRACE(level, args ...) QDF_TRACE(QDF_MODULE_ID_QDF, level, ## args)
45 #else
46 #define PTT_TRACE(level, args ...)
47 #endif
48 
49 #ifdef PTT_SOCK_DEBUG_VERBOSE
50 /* Utility function to perform a hex dump */
51 static void ptt_sock_dump_buf(const unsigned char *pbuf, int cnt)
52 {
53 	int i;
54 
55 	for (i = 0; i < cnt; i++) {
56 		if ((i % 16) == 0)
57 			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
58 				  "\n%pK:", pbuf);
59 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, " %02X",
60 			  *pbuf);
61 		pbuf++;
62 	}
63 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, "\n");
64 }
65 #endif
66 
67 /**
68  * nl_srv_ucast_ptt() - Wrapper function to send ucast msgs to PTT
69  * @skb: sk buffer pointer
70  * @dst_pid: Destination PID
71  * @flag: flags
72  *
73  * Sends the ucast message to PTT with generic nl socket if CNSS_GENL
74  * is enabled. Else, use the legacy netlink socket to send.
75  *
76  * Return: zero on success, error code otherwise
77  */
78 static int nl_srv_ucast_ptt(struct sk_buff *skb, int dst_pid, int flag)
79 {
80 #ifdef CNSS_GENL
81 	return nl_srv_ucast(skb, dst_pid, flag, ANI_NL_MSG_PUMAC,
82 				CLD80211_MCGRP_DIAG_EVENTS);
83 #else
84 	return nl_srv_ucast(skb, dst_pid, flag);
85 #endif
86 }
87 
88 /**
89  * nl_srv_bcast_ptt() - Wrapper function to send bcast msgs to DIAG mcast group
90  * @skb: sk buffer pointer
91  *
92  * Sends the bcast message to DIAG multicast group with generic nl socket
93  * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send.
94  *
95  * Return: zero on success, error code otherwise
96  */
97 static int nl_srv_bcast_ptt(struct sk_buff *skb)
98 {
99 #ifdef CNSS_GENL
100 	return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC);
101 #else
102 	return nl_srv_bcast(skb);
103 #endif
104 }
105 
106 /**
107  * ptt_sock_send_msg_to_app() - Send nl message to user space
108  * wmsg: Message header
109  * radio: Unit number of the radio
110  * src_mod: Message type
111  * pid: Process ID to which message will be unicast. Message
112  * will be broadcast when PID is INVALID_PID
113  *
114  * Utility function to send a netlink message to an application in user space
115  *
116  * Return: 0 on success and negative value on failure
117  */
118 int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid)
119 {
120 	int err = -1;
121 	int payload_len;
122 	int tot_msg_len;
123 	tAniNlHdr *wnl;
124 	struct sk_buff *skb;
125 	struct nlmsghdr *nlh;
126 	int wmsg_length = be16_to_cpu(wmsg->length);
127 	static int nlmsg_seq;
128 
129 	if (radio < 0 || radio > ANI_MAX_RADIOS) {
130 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s: invalid radio id [%d]\n",
131 			  __func__, radio);
132 		return -EINVAL;
133 	}
134 	payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(*wmsg);
135 	tot_msg_len = NLMSG_SPACE(payload_len);
136 	skb = dev_alloc_skb(tot_msg_len);
137 	if (skb  == NULL) {
138 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
139 			  "%s: dev_alloc_skb() failed for msg size[%d]\n",
140 			  __func__, tot_msg_len);
141 		return -ENOMEM;
142 	}
143 	nlh =
144 		nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len,
145 			  NLM_F_REQUEST);
146 	if (NULL == nlh) {
147 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
148 			  "%s: nlmsg_put() failed for msg size[%d]\n", __func__,
149 			  tot_msg_len);
150 		kfree_skb(skb);
151 		return -ENOMEM;
152 	}
153 	wnl = (tAniNlHdr *) nlh;
154 	wnl->radio = radio;
155 	memcpy(&wnl->wmsg, wmsg, wmsg_length);
156 #ifdef PTT_SOCK_DEBUG_VERBOSE
157 	ptt_sock_dump_buf((const unsigned char *)skb->data, skb->len);
158 #endif
159 
160 	if (pid != INVALID_PID)
161 		err = nl_srv_ucast_ptt(skb, pid, MSG_DONTWAIT);
162 	else
163 		err = nl_srv_bcast_ptt(skb);
164 
165 	if (err)
166 		PTT_TRACE(QDF_TRACE_LEVEL_INFO,
167 			  "%s:Failed sending Msg Type [0x%X] to pid[%d]\n",
168 			  __func__, be16_to_cpu(wmsg->type), pid);
169 	return err;
170 }
171 
172 #ifndef CNSS_GENL
173 /*
174  * Process tregisteration request and send registration response messages
175  * to the PTT Socket App in user space
176  */
177 static void ptt_sock_proc_reg_req(tAniHdr *wmsg, int radio)
178 {
179 	struct sAniAppRegReq *reg_req;
180 	struct sAniNlAppRegRsp rspmsg;
181 
182 	reg_req = (struct sAniAppRegReq *) (wmsg + 1);
183 	memset((char *)&rspmsg, 0, sizeof(rspmsg));
184 	/* send reg response message to the application */
185 	rspmsg.ret = ANI_NL_MSG_OK;
186 	rspmsg.regReq.type = reg_req->type;
187 	/*Save the pid */
188 	ptt_pid = reg_req->pid;
189 	rspmsg.regReq.pid = reg_req->pid;
190 	rspmsg.wniHdr.type = cpu_to_be16(ANI_MSG_APP_REG_RSP);
191 	rspmsg.wniHdr.length = cpu_to_be16(sizeof(rspmsg));
192 	if (ptt_sock_send_msg_to_app((tAniHdr *) &rspmsg.wniHdr, radio,
193 				     ANI_NL_MSG_PUMAC, ptt_pid) < 0) {
194 		PTT_TRACE(QDF_TRACE_LEVEL_INFO,
195 			  "%s: Error sending ANI_MSG_APP_REG_RSP to pid[%d]\n",
196 			  __func__, ptt_pid);
197 	}
198 }
199 
200 /*
201  * Process all the messages from the PTT Socket App in user space
202  */
203 static void ptt_proc_pumac_msg(struct sk_buff *skb, tAniHdr *wmsg, int radio)
204 {
205 	u16 ani_msg_type = be16_to_cpu(wmsg->type);
206 
207 	switch (ani_msg_type) {
208 	case ANI_MSG_APP_REG_REQ:
209 		PTT_TRACE(QDF_TRACE_LEVEL_INFO,
210 			  "%s: Received ANI_MSG_APP_REG_REQ [0x%X]\n", __func__,
211 			  ani_msg_type);
212 		ptt_sock_proc_reg_req(wmsg, radio);
213 		break;
214 	default:
215 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
216 			  "%s: Received Unknown Msg Type[0x%X]\n", __func__,
217 			  ani_msg_type);
218 		break;
219 	}
220 }
221 
222 /*
223  * Process all the Netlink messages from PTT Socket app in user space
224  */
225 static int ptt_sock_rx_nlink_msg(struct sk_buff *skb)
226 {
227 	tAniNlHdr *wnl;
228 	int radio;
229 	int type;
230 
231 	wnl = (tAniNlHdr *) skb->data;
232 	radio = wnl->radio;
233 	type = wnl->nlh.nlmsg_type;
234 	switch (type) {
235 	case ANI_NL_MSG_PUMAC:  /* Message from the PTT socket APP */
236 		PTT_TRACE(QDF_TRACE_LEVEL_INFO,
237 			  "%s: Received ANI_NL_MSG_PUMAC Msg [0x%X]\n",
238 			  __func__, type);
239 		ptt_proc_pumac_msg(skb, &wnl->wmsg, radio);
240 		break;
241 	default:
242 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s: Unknown NL Msg [0x%X]\n",
243 			  __func__, type);
244 		break;
245 	}
246 	return 0;
247 }
248 #endif
249 
250 #ifdef CNSS_GENL
251 /**
252  * ptt_cmd_handler() - Handler function for PTT commands
253  * @data: Data to be parsed
254  * @data_len: Length of the data received
255  * @ctx: Registered context reference
256  * @pid: Process id of the user space application
257  *
258  * This function handles the command from PTT user space application
259  *
260  * Return: None
261  */
262 static void ptt_cmd_handler(const void *data, int data_len, void *ctx, int pid)
263 {
264 	uint16_t length;
265 	struct sptt_app_reg_req *payload;
266 	struct nlattr *tb[CLD80211_ATTR_MAX + 1];
267 
268 	/*
269 	 * audit note: it is ok to pass a NULL policy here since a
270 	 * length check on the data is added later already
271 	 */
272 	if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX,
273 				    data, data_len, NULL)) {
274 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "Invalid ATTR");
275 		return;
276 	}
277 
278 	if (!tb[CLD80211_ATTR_DATA]) {
279 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "attr ATTR_DATA failed");
280 		return;
281 	}
282 
283 	if (nla_len(tb[CLD80211_ATTR_DATA]) < sizeof(struct sptt_app_reg_req)) {
284 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s:attr length check fails\n",
285 			__func__);
286 		return;
287 	}
288 
289 	payload = (struct sptt_app_reg_req *)(nla_data(tb[CLD80211_ATTR_DATA]));
290 	length = be16_to_cpu(payload->wmsg.length);
291 	if ((USHRT_MAX - length) < (sizeof(payload->radio) + sizeof(tAniHdr))) {
292 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR,
293 			"u16 overflow length %d %zu %zu",
294 			length,
295 			sizeof(payload->radio),
296 			sizeof(tAniHdr));
297 		return;
298 	}
299 
300 	if (nla_len(tb[CLD80211_ATTR_DATA]) <  (length +
301 						sizeof(payload->radio) +
302 						sizeof(tAniHdr))) {
303 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "ATTR_DATA len check failed");
304 		return;
305 	}
306 
307 	switch (payload->wmsg.type) {
308 	case ANI_MSG_APP_REG_REQ:
309 		ptt_sock_send_msg_to_app(&payload->wmsg, payload->radio,
310 							ANI_NL_MSG_PUMAC, pid);
311 		break;
312 	default:
313 		PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "Unknown msg type %d",
314 							payload->wmsg.type);
315 		break;
316 	}
317 }
318 
319 /**
320  * ptt_sock_activate_svc() - API to register PTT/PUMAC command handler
321  *
322  * API to register the PTT/PUMAC command handlers. Argument @pAdapter
323  * is sent for prototype compatibility between new genl and legacy
324  * implementation
325  *
326  * Return: 0
327  */
328 int ptt_sock_activate_svc(void)
329 {
330 	register_cld_cmd_cb(ANI_NL_MSG_PUMAC, ptt_cmd_handler, NULL);
331 	register_cld_cmd_cb(ANI_NL_MSG_PTT, ptt_cmd_handler, NULL);
332 	return 0;
333 }
334 
335 /**
336  * ptt_sock_deactivate_svc() - Dummy API to deactivate PTT service
337  *
338  * Return: Void
339  */
340 void ptt_sock_deactivate_svc(void)
341 {
342 }
343 #else
344 
345 /**
346  * ptt_sock_activate_svc() - activate PTT service
347  *
348  * Return: 0
349  */
350 int ptt_sock_activate_svc(void)
351 {
352 	ptt_pid = INVALID_PID;
353 	nl_srv_register(ANI_NL_MSG_PUMAC, ptt_sock_rx_nlink_msg);
354 	nl_srv_register(ANI_NL_MSG_PTT, ptt_sock_rx_nlink_msg);
355 	return 0;
356 }
357 
358 /**
359  * ptt_sock_deactivate_svc() - deactivate PTT service
360  *
361  * Return: Void
362  */
363 void ptt_sock_deactivate_svc(void)
364 {
365 	ptt_pid = INVALID_PID;
366 }
367 #endif
368 #endif /* PTT_SOCK_SVC_ENABLE */
369