1 /*
2  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: Implement API's specific to CoAP component.
19  */
20 
21 #include <wmi_unified_priv.h>
22 #include "wmi.h"
23 #include "ol_defines.h"
24 
25 /*
26  * send_coap_add_pattern_cmd_tlv() - Send wmi cmd for adding CoAP pattern
27  * @wmi_handle: wmi handle
28  * @param: parameter for CoAP add pattern
29  *
30  * Return: QDF_STATUS
31  */
32 static QDF_STATUS
send_coap_add_pattern_cmd_tlv(wmi_unified_t wmi_handle,struct coap_offload_reply_param * param)33 send_coap_add_pattern_cmd_tlv(wmi_unified_t wmi_handle,
34 			      struct coap_offload_reply_param *param)
35 {
36 	WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param *cmd;
37 	wmi_buf_t buf;
38 	QDF_STATUS status;
39 	uint8_t *buf_ptr;
40 	uint32_t len, coapmsg_len_align, verify_len_align;
41 
42 	wmi_debug("vdev id %d pattern id %d timeout %d src ip 0x%x:%d coap msg len %d",
43 		  param->vdev_id, param->pattern_id, param->cache_timeout,
44 		  param->src_ip_v4, param->src_udp_port,
45 		  param->coapmsg_len);
46 
47 	wmi_debug("filter: dest ip 0x%x:%d is bc %d verify offset %d len %d",
48 		  param->dest_ip_v4, param->dest_udp_port,
49 		  param->dest_ip_v4_is_bc, param->verify_offset,
50 		  param->verify_len);
51 
52 	if (!param->verify || !param->verify_len ||
53 	    !param->coapmsg || !param->coapmsg_len) {
54 		wmi_err("invalid param");
55 		return QDF_STATUS_E_INVAL;
56 	}
57 
58 	coapmsg_len_align = qdf_align(param->coapmsg_len, 4);
59 	verify_len_align = qdf_align(param->verify_len, 4);
60 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + coapmsg_len_align +
61 		WMI_TLV_HDR_SIZE + verify_len_align;
62 	buf = wmi_buf_alloc(wmi_handle, len);
63 	if (!buf)
64 		return QDF_STATUS_E_NOMEM;
65 
66 	buf_ptr = wmi_buf_data(buf);
67 	cmd = (WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param *)buf_ptr;
68 
69 	WMITLV_SET_HDR(&cmd->tlv_header,
70 		WMITLV_TAG_STRUC_WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param,
71 		WMITLV_GET_STRUCT_TLVLEN(
72 			WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param));
73 
74 	cmd->vdev_id = param->vdev_id;
75 	cmd->pattern_id = param->pattern_id;
76 	cmd->timeout = param->cache_timeout;
77 	WMI_COAP_IPV6_SET(cmd->pattern_type, 0);
78 	WMI_COAP_ADDR_TYPE_SET(cmd->pattern_type,
79 			       param->dest_ip_v4_is_bc ? 1 : 0);
80 	qdf_mem_copy(cmd->match_udp_ip.ipv4_addr, &param->dest_ip_v4,
81 		     sizeof(param->dest_ip_v4));
82 	cmd->match_udp_port = param->dest_udp_port;
83 	qdf_mem_copy(cmd->udp_local_ip.ipv4_addr, &param->src_ip_v4,
84 		     sizeof(param->src_ip_v4));
85 	cmd->udp_local_port = param->src_udp_port;
86 	cmd->verify_offset = param->verify_offset;
87 	cmd->verify_len = param->verify_len;
88 	cmd->coapmsg_len = param->coapmsg_len;
89 
90 	buf_ptr += sizeof(*cmd);
91 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, verify_len_align);
92 	buf_ptr += WMI_TLV_HDR_SIZE;
93 	qdf_mem_copy(buf_ptr, param->verify, param->verify_len);
94 
95 	buf_ptr += verify_len_align;
96 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, coapmsg_len_align);
97 	buf_ptr += WMI_TLV_HDR_SIZE;
98 	qdf_mem_copy(buf_ptr, param->coapmsg, param->coapmsg_len);
99 	buf_ptr += coapmsg_len_align;
100 
101 	wmi_mtrace(WMI_WOW_COAP_ADD_PATTERN_CMDID,
102 		   cmd->vdev_id, cmd->pattern_id);
103 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
104 				      WMI_WOW_COAP_ADD_PATTERN_CMDID);
105 	if (status != QDF_STATUS_SUCCESS) {
106 		wmi_err("Failed to send wow coap add pattern command %d",
107 			status);
108 		wmi_buf_free(buf);
109 	}
110 
111 	return status;
112 }
113 
114 /*
115  * send_coap_del_pattern_cmd_tlv() - Send wmi cmd for deleting CoAP pattern
116  * @wmi_handle: wmi handle
117  * @vdev_id: vdev id
118  * @pattern_id: pattern id
119  *
120  * Return: QDF_STATUS
121  */
122 static QDF_STATUS
send_coap_del_pattern_cmd_tlv(wmi_unified_t wmi_handle,uint8_t vdev_id,uint32_t pattern_id)123 send_coap_del_pattern_cmd_tlv(wmi_unified_t wmi_handle,
124 			      uint8_t vdev_id, uint32_t pattern_id)
125 {
126 	WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param *cmd;
127 	wmi_buf_t buf;
128 	QDF_STATUS status;
129 	uint32_t len = sizeof(*cmd);
130 
131 	wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id);
132 
133 	buf = wmi_buf_alloc(wmi_handle, len);
134 	if (!buf)
135 		return QDF_STATUS_E_NOMEM;
136 
137 	cmd = (WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param *)wmi_buf_data(buf);
138 
139 	WMITLV_SET_HDR(&cmd->tlv_header,
140 		 WMITLV_TAG_STRUC_WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param,
141 		 WMITLV_GET_STRUCT_TLVLEN(
142 			WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param));
143 
144 	cmd->vdev_id = vdev_id;
145 	cmd->pattern_id = pattern_id;
146 	wmi_mtrace(WMI_WOW_COAP_DEL_PATTERN_CMDID,
147 		   cmd->vdev_id, cmd->pattern_id);
148 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
149 				      WMI_WOW_COAP_DEL_PATTERN_CMDID);
150 	if (status != QDF_STATUS_SUCCESS) {
151 		wmi_err("Failed to send wow coap del pattern command %d",
152 			status);
153 		wmi_buf_free(buf);
154 	}
155 
156 	return status;
157 }
158 
159 /*
160  * send_coap_add_pattern_cmd_tlv() - Send wmi cmd for adding CoAP keepalive
161  * pattern
162  * @wmi_handle: wmi handle
163  * @param: parameter for CoAP add pattern
164  *
165  * Return: QDF_STATUS
166  */
167 static QDF_STATUS
send_coap_add_keepalive_pattern_cmd_tlv(wmi_unified_t wmi_handle,struct coap_offload_periodic_tx_param * param)168 send_coap_add_keepalive_pattern_cmd_tlv(wmi_unified_t wmi_handle,
169 			struct coap_offload_periodic_tx_param *param)
170 {
171 	WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param *cmd;
172 	wmi_buf_t buf;
173 	QDF_STATUS status;
174 	uint8_t *buf_ptr;
175 	uint32_t len, coapmsg_len_align;
176 
177 	wmi_debug("vdev id %d pattern id %d ip src 0x%x:%d dest 0x%x:%d bc %d timeout %d",
178 		  param->vdev_id, param->pattern_id, param->src_ip_v4,
179 		  param->src_udp_port, param->dest_ip_v4,
180 		  param->dest_udp_port, param->dest_ip_v4_is_bc,
181 		  param->timeout);
182 
183 	if (!param->coapmsg || !param->coapmsg_len) {
184 		wmi_err("invalid CoAP message");
185 		return QDF_STATUS_E_INVAL;
186 	}
187 
188 	coapmsg_len_align = qdf_align(param->coapmsg_len, 4);
189 	len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + coapmsg_len_align;
190 	buf = wmi_buf_alloc(wmi_handle, len);
191 	if (!buf)
192 		return QDF_STATUS_E_NOMEM;
193 
194 	buf_ptr = wmi_buf_data(buf);
195 	cmd = (WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param *)buf_ptr;
196 
197 	WMITLV_SET_HDR(&cmd->tlv_header,
198 	WMITLV_TAG_STRUC_WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param,
199 	WMITLV_GET_STRUCT_TLVLEN(
200 		WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param));
201 
202 	cmd->vdev_id = param->vdev_id;
203 	cmd->pattern_id = param->pattern_id;
204 
205 	/* only support IPv4 in current stage */
206 	WMI_COAP_IPV6_SET(cmd->pattern_type, 0);
207 	WMI_COAP_ADDR_TYPE_SET(cmd->pattern_type,
208 			       param->dest_ip_v4_is_bc ? 1 : 0);
209 	qdf_mem_copy(cmd->udp_remote_ip.ipv4_addr, &param->dest_ip_v4,
210 		     sizeof(param->dest_ip_v4));
211 	cmd->udp_remote_port = param->dest_udp_port;
212 	qdf_mem_copy(cmd->udp_local_ip.ipv4_addr, &param->src_ip_v4,
213 		     sizeof(param->src_ip_v4));
214 	cmd->udp_local_port = param->src_udp_port;
215 	cmd->timeout = param->timeout;
216 	cmd->coapmsg_len = param->coapmsg_len;
217 
218 	buf_ptr += sizeof(*cmd);
219 	WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, coapmsg_len_align);
220 	buf_ptr += WMI_TLV_HDR_SIZE;
221 	qdf_mem_copy(buf_ptr, param->coapmsg, param->coapmsg_len);
222 	buf_ptr += coapmsg_len_align;
223 
224 	wmi_mtrace(WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMDID,
225 		   cmd->vdev_id, cmd->pattern_id);
226 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
227 				      WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMDID);
228 	if (status != QDF_STATUS_SUCCESS) {
229 		wmi_err("Failed to send wow coap add keepalive pattern command %d",
230 			status);
231 		wmi_buf_free(buf);
232 	}
233 
234 	return status;
235 }
236 
237 /*
238  * send_coap_del_pattern_cmd_tlv() - Send wmi cmd for deleting CoAP
239  * keepalive pattern
240  * @wmi_handle: wmi handle
241  * @vdev_id: vdev id
242  * @pattern_id: pattern id
243  *
244  * Return: QDF_STATUS
245  */
246 static QDF_STATUS
send_coap_del_keepalive_pattern_cmd_tlv(wmi_unified_t wmi_handle,uint8_t vdev_id,uint32_t pattern_id)247 send_coap_del_keepalive_pattern_cmd_tlv(wmi_unified_t wmi_handle,
248 					uint8_t vdev_id, uint32_t pattern_id)
249 {
250 	WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param *cmd;
251 	wmi_buf_t buf;
252 	QDF_STATUS status;
253 	uint8_t *buf_ptr;
254 	uint32_t len = sizeof(*cmd);
255 
256 	wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id);
257 	buf = wmi_buf_alloc(wmi_handle, len);
258 	if (!buf)
259 		return QDF_STATUS_E_NOMEM;
260 
261 	buf_ptr = wmi_buf_data(buf);
262 	cmd = (WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param *)buf_ptr;
263 
264 	WMITLV_SET_HDR(&cmd->tlv_header,
265 		WMITLV_TAG_STRUC_WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param,
266 		WMITLV_GET_STRUCT_TLVLEN(
267 			WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param));
268 
269 	cmd->vdev_id = vdev_id;
270 	cmd->pattern_id = pattern_id;
271 	wmi_mtrace(WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMDID,
272 		   cmd->vdev_id, cmd->pattern_id);
273 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
274 				      WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMDID);
275 	if (status != QDF_STATUS_SUCCESS) {
276 		wmi_err("Failed to send wow coap del keepalive pattern command %d",
277 			status);
278 		wmi_buf_free(buf);
279 	}
280 
281 	return status;
282 }
283 
284 /*
285  * send_coap_cache_get_cmd_tlv() - Send wmi cmd for getting cached CoAP
286  * messages
287  * @wmi_handle: wmi handle
288  * @vdev_id: vdev id
289  * @pattern_id: pattern id
290  *
291  * Return: QDF_STATUS
292  */
293 static QDF_STATUS
send_coap_cache_get_cmd_tlv(wmi_unified_t wmi_handle,uint8_t vdev_id,uint32_t pattern_id)294 send_coap_cache_get_cmd_tlv(wmi_unified_t wmi_handle,
295 			    uint8_t vdev_id, uint32_t pattern_id)
296 {
297 	WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param *cmd;
298 	wmi_buf_t buf;
299 	QDF_STATUS status;
300 	uint32_t len = sizeof(*cmd);
301 
302 	wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id);
303 	buf = wmi_buf_alloc(wmi_handle, len);
304 	if (!buf)
305 		return QDF_STATUS_E_NOMEM;
306 
307 	cmd = (WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param *)wmi_buf_data(buf);
308 
309 	WMITLV_SET_HDR(&cmd->tlv_header,
310 		WMITLV_TAG_STRUC_WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param,
311 		WMITLV_GET_STRUCT_TLVLEN(
312 			WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param));
313 
314 	cmd->vdev_id = vdev_id;
315 	cmd->pattern_id = pattern_id;
316 	wmi_mtrace(WMI_WOW_COAP_GET_BUF_INFO_CMDID,
317 		   cmd->vdev_id, cmd->pattern_id);
318 	status = wmi_unified_cmd_send(wmi_handle, buf, len,
319 				      WMI_WOW_COAP_GET_BUF_INFO_CMDID);
320 	if (status != QDF_STATUS_SUCCESS) {
321 		wmi_err("Failed to send wow coap get buf info command %d",
322 			status);
323 		wmi_buf_free(buf);
324 	}
325 
326 	return status;
327 }
328 
329 /**
330  * coap_extract_buf_info_tlv() - Extract CoAP buf info event
331  * @wmi_handle: wmi handle
332  * @evt_buf: Pointer to the event buffer
333  * @info: pointer to CoAP buf info
334  *
335  * The caller needs to free any possible nodes in info->info_list
336  * regardless of failure or success.
337  *
338  * Return: QDF_STATUS
339  */
340 static QDF_STATUS
coap_extract_buf_info_tlv(wmi_unified_t wmi_handle,void * evt_buf,struct coap_buf_info * info)341 coap_extract_buf_info_tlv(wmi_unified_t wmi_handle, void *evt_buf,
342 			  struct coap_buf_info *info)
343 {
344 	WMI_WOW_COAP_BUF_INFO_EVENT_fixed_param *buf_info_ev;
345 	WMI_WOW_COAP_BUF_INFO_EVENTID_param_tlvs *param_buf = evt_buf;
346 	wmi_coap_tuple *tuple;
347 	uint8_t *payload;
348 	uint32_t num_tuple, num_payload;
349 	struct coap_buf_node *buf_node;
350 	int i, j;
351 
352 	buf_info_ev = param_buf->fixed_param;
353 	if (!buf_info_ev) {
354 		wmi_debug("received null event data from target");
355 		return QDF_STATUS_E_INVAL;
356 	}
357 
358 	if (buf_info_ev->vdev_id > WLAN_MAX_VDEVS) {
359 		wmi_debug("received invalid vdev_id %d",
360 			  buf_info_ev->vdev_id);
361 		return QDF_STATUS_E_INVAL;
362 	}
363 
364 	info->vdev_id = buf_info_ev->vdev_id;
365 	info->req_id = buf_info_ev->pattern_id;
366 	info->more_info = buf_info_ev->more_tuples;
367 
368 	num_tuple = param_buf->num_coap_tuple;
369 	num_payload = param_buf->num_payloads;
370 	for (i = 0, j = 0; i < num_tuple && j < num_payload; i++) {
371 		tuple = &param_buf->coap_tuple[i];
372 		if (!tuple->payload_len) {
373 			wmi_err("idx %d: invalid payload len 0", i);
374 			continue;
375 		}
376 
377 		payload = &param_buf->payloads[j];
378 		j += qdf_align(tuple->payload_len, 4);
379 		if (j > num_payload) {
380 			wmi_err("idx %d: payload len overflow, pos %d - total %d",
381 				i, j, num_payload);
382 			return QDF_STATUS_E_INVAL;
383 		}
384 
385 		buf_node = qdf_mem_malloc(sizeof(*buf_node));
386 		if (!buf_node)
387 			return QDF_STATUS_E_NOMEM;
388 
389 		buf_node->payload = qdf_mem_malloc(tuple->payload_len);
390 		if (!buf_node->payload) {
391 			qdf_mem_free(buf_node);
392 			return QDF_STATUS_E_NOMEM;
393 		}
394 
395 		buf_node->tsf = tuple->tsf;
396 		qdf_mem_copy(&buf_node->src_ip, tuple->src_ip.ipv4_addr,
397 			     sizeof(buf_node->src_ip));
398 		buf_node->len = tuple->payload_len;
399 		qdf_mem_copy(buf_node->payload, payload, buf_node->len);
400 		qdf_list_insert_back(&info->info_list, &buf_node->node);
401 
402 		wmi_debug("idx %d: src ip 0x%x tsf 0x%llx payload len %d",
403 			  i, buf_node->src_ip, buf_node->tsf, buf_node->len);
404 	}
405 
406 	wmi_debug("vdev_id %d req_id %d num_tuple %d payload len %d more info %d",
407 		  info->vdev_id, info->req_id, num_tuple,
408 		  num_payload, info->more_info);
409 	return QDF_STATUS_SUCCESS;
410 }
411 
412 /**
413  * wmi_coap_attach_tlv() - attach CoAP tlv handlers
414  * @wmi_handle: wmi handle
415  *
416  * Return: void
417  */
wmi_coap_attach_tlv(wmi_unified_t wmi_handle)418 void wmi_coap_attach_tlv(wmi_unified_t wmi_handle)
419 {
420 	struct wmi_ops *ops = wmi_handle->ops;
421 
422 	ops->send_coap_add_pattern_cmd = send_coap_add_pattern_cmd_tlv;
423 	ops->send_coap_del_pattern_cmd = send_coap_del_pattern_cmd_tlv;
424 	ops->send_coap_add_keepalive_pattern_cmd =
425 		send_coap_add_keepalive_pattern_cmd_tlv;
426 	ops->send_coap_del_keepalive_pattern_cmd =
427 		send_coap_del_keepalive_pattern_cmd_tlv;
428 	ops->send_coap_cache_get_cmd = send_coap_cache_get_cmd_tlv;
429 	ops->extract_coap_buf_info = coap_extract_buf_info_tlv;
430 }
431