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, ¶m->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, ¶m->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, ¶m->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, ¶m->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 = ¶m_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 = ¶m_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