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: contains CoAP target if functions
19  */
20 #include <wlan_coap_main.h>
21 #include <target_if_coap.h>
22 #include <wmi_unified_coap_api.h>
23 
24 /**
25  * target_if_wow_coap_buf_info_event_handler() - function to handle CoAP
26  * buf info event from firmware.
27  * @scn: scn handle
28  * @data: data buffer for event
29  * @datalen: data length
30  *
31  * Return: status of operation.
32  */
33 static int
target_if_wow_coap_buf_info_event_handler(ol_scn_t scn,uint8_t * data,uint32_t datalen)34 target_if_wow_coap_buf_info_event_handler(ol_scn_t scn, uint8_t *data,
35 					  uint32_t datalen)
36 {
37 	QDF_STATUS status;
38 	struct wlan_objmgr_psoc *psoc;
39 	struct wmi_unified *wmi_handle;
40 	struct wlan_objmgr_vdev *vdev = NULL;
41 	struct wlan_coap_comp_priv *coap_priv;
42 	struct coap_buf_info info = {0};
43 	struct coap_buf_node *cur, *next;
44 
45 	if (!scn || !data) {
46 		coap_err("scn: 0x%pK, data: 0x%pK", scn, data);
47 		return -EINVAL;
48 	}
49 
50 	psoc = target_if_get_psoc_from_scn_hdl(scn);
51 	if (!psoc) {
52 		coap_err("null psoc");
53 		return -EINVAL;
54 	}
55 
56 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
57 	if (!wmi_handle) {
58 		coap_err("wmi_handle is null");
59 		return -EINVAL;
60 	}
61 
62 	qdf_list_create(&info.info_list, 0);
63 	status = wmi_unified_coap_extract_buf_info(wmi_handle, data,
64 						   &info);
65 	if (QDF_IS_STATUS_ERROR(status))
66 		goto out;
67 
68 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, info.vdev_id,
69 						    WLAN_COAP_ID);
70 	if (!vdev) {
71 		coap_err("vdev is NULL, vdev_id: %d", info.vdev_id);
72 		status = QDF_STATUS_E_INVAL;
73 		goto out;
74 	}
75 
76 	coap_priv = wlan_get_vdev_coap_obj(vdev);
77 	if (!coap_priv->cache_get_cbk || !coap_priv->cache_get_context) {
78 		coap_err("req id %d: callback or context is NULL",
79 			 coap_priv->req_id);
80 		status = QDF_STATUS_E_INVAL;
81 		goto out;
82 	}
83 
84 	coap_priv->cache_get_cbk(coap_priv->cache_get_context, &info);
85 out:
86 	qdf_list_for_each_del(&info.info_list, cur, next, node) {
87 		qdf_list_remove_node(&info.info_list, &cur->node);
88 		qdf_mem_free(cur->payload);
89 		qdf_mem_free(cur);
90 	}
91 
92 	if (vdev)
93 		wlan_objmgr_vdev_release_ref(vdev, WLAN_COAP_ID);
94 	return qdf_status_to_os_return(status);
95 }
96 
97 /**
98  * target_if_coap_register_event_handler() - Register CoAP related wmi events
99  * @psoc: psoc handle
100  *
101  * Register CoAP related WMI events
102  *
103  * return: QDF_STATUS
104  */
105 static QDF_STATUS
target_if_coap_register_event_handler(struct wlan_objmgr_psoc * psoc)106 target_if_coap_register_event_handler(struct wlan_objmgr_psoc *psoc)
107 {
108 	QDF_STATUS ret_val;
109 	struct wmi_unified *wmi_handle;
110 
111 	if (!psoc) {
112 		coap_err("PSOC is NULL!");
113 		return QDF_STATUS_E_NULL_VALUE;
114 	}
115 
116 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
117 	if (!wmi_handle) {
118 		coap_err("wmi_handle is null");
119 		return QDF_STATUS_E_INVAL;
120 	}
121 
122 	ret_val = wmi_unified_register_event_handler(wmi_handle,
123 			wmi_wow_coap_buf_info_eventid,
124 			target_if_wow_coap_buf_info_event_handler,
125 			WMI_RX_WORK_CTX);
126 	if (QDF_IS_STATUS_ERROR(ret_val))
127 		coap_err("Failed to register coap buf info event cb");
128 
129 	return ret_val;
130 }
131 
132 /**
133  * target_if_coap_unregister_event_handler() - Unregister CoAP related wmi
134  * events
135  * @psoc: psoc handle
136  *
137  * Register CoAP related WMI events
138  *
139  * return: QDF_STATUS
140  */
141 static QDF_STATUS
target_if_coap_unregister_event_handler(struct wlan_objmgr_psoc * psoc)142 target_if_coap_unregister_event_handler(struct wlan_objmgr_psoc *psoc)
143 {
144 	struct wmi_unified *wmi_handle;
145 
146 	if (!psoc) {
147 		coap_err("PSOC is NULL!");
148 		return QDF_STATUS_E_INVAL;
149 	}
150 
151 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
152 	if (!wmi_handle) {
153 		coap_err("wmi_handle is null");
154 		return QDF_STATUS_E_INVAL;
155 	}
156 	wmi_unified_unregister_event_handler(wmi_handle,
157 					     wmi_wow_coap_buf_info_eventid);
158 
159 	return QDF_STATUS_SUCCESS;
160 }
161 
162 /**
163  * target_if_coap_offload_reply_enable() - enable CoAP offload reply
164  * @vdev: pointer to vdev object
165  * @param: parameters for CoAP offload reply
166  *
167  * Return: status of operation
168  */
169 static QDF_STATUS
target_if_coap_offload_reply_enable(struct wlan_objmgr_vdev * vdev,struct coap_offload_reply_param * param)170 target_if_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev,
171 				    struct coap_offload_reply_param *param)
172 {
173 	wmi_unified_t wmi_handle;
174 	struct wlan_objmgr_pdev *pdev;
175 
176 	pdev = wlan_vdev_get_pdev(vdev);
177 	wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
178 	if (!wmi_handle) {
179 		coap_err("Invalid PDEV WMI handle");
180 		return QDF_STATUS_E_FAILURE;
181 	}
182 
183 	return wmi_unified_coap_add_pattern_cmd(wmi_handle, param);
184 }
185 
186 /**
187  * target_if_coap_offload_reply_disable() - disable CoAP offload reply
188  * @vdev: pointer to vdev object
189  * @req_id: request id
190  *
191  * Return: status of operation
192  */
193 static QDF_STATUS
target_if_coap_offload_reply_disable(struct wlan_objmgr_vdev * vdev,uint32_t req_id)194 target_if_coap_offload_reply_disable(struct wlan_objmgr_vdev *vdev,
195 				     uint32_t req_id)
196 {
197 	wmi_unified_t wmi_handle;
198 	struct wlan_objmgr_pdev *pdev;
199 
200 	pdev = wlan_vdev_get_pdev(vdev);
201 	wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
202 	if (!wmi_handle) {
203 		coap_err("Invalid PDEV WMI handle");
204 		return QDF_STATUS_E_FAILURE;
205 	}
206 
207 	return wmi_unified_coap_del_pattern_cmd(wmi_handle,
208 						wlan_vdev_get_id(vdev),
209 						req_id);
210 }
211 
212 /**
213  * target_if_coap_offload_periodic_tx_enable() - enable CoAP offload
214  * periodic transmitting
215  * @vdev: pointer to vdev object
216  * @param: parameters for CoAP periodic transmitting
217  *
218  * Return: status of operation
219  */
220 static QDF_STATUS
target_if_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev * vdev,struct coap_offload_periodic_tx_param * param)221 target_if_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev,
222 			struct coap_offload_periodic_tx_param *param)
223 {
224 	wmi_unified_t wmi_handle;
225 	struct wlan_objmgr_pdev *pdev;
226 
227 	pdev = wlan_vdev_get_pdev(vdev);
228 	wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
229 	if (!wmi_handle) {
230 		coap_err("Invalid PDEV WMI handle");
231 		return QDF_STATUS_E_FAILURE;
232 	}
233 
234 	return wmi_unified_coap_add_keepalive_pattern_cmd(wmi_handle, param);
235 }
236 
237 /**
238  * target_if_coap_offload_periodic_tx_disable() - disable CoAP offload
239  * periodic transmitting
240  * @vdev: pointer to vdev object
241  * @req_id: request id
242  *
243  * Return: status of operation
244  */
245 static QDF_STATUS
target_if_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev * vdev,uint32_t req_id)246 target_if_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev,
247 					   uint32_t req_id)
248 {
249 	wmi_unified_t wmi_handle;
250 	struct wlan_objmgr_pdev *pdev;
251 	uint8_t vdev_id;
252 
253 	pdev = wlan_vdev_get_pdev(vdev);
254 	wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
255 	if (!wmi_handle) {
256 		coap_err("Invalid PDEV WMI handle");
257 		return QDF_STATUS_E_FAILURE;
258 	}
259 
260 	vdev_id = wlan_vdev_get_id(vdev);
261 	return wmi_unified_coap_del_keepalive_pattern_cmd(wmi_handle,
262 							  vdev_id, req_id);
263 }
264 
265 /**
266  * target_if_coap_offload_cache_get() - get cached CoAP messages
267  * @vdev: pointer to vdev object
268  * @req_id: request id
269  *
270  * Return: status of operation
271  */
272 static QDF_STATUS
target_if_coap_offload_cache_get(struct wlan_objmgr_vdev * vdev,uint32_t req_id)273 target_if_coap_offload_cache_get(struct wlan_objmgr_vdev *vdev,
274 				 uint32_t req_id)
275 {
276 	wmi_unified_t wmi_handle;
277 	struct wlan_objmgr_pdev *pdev;
278 
279 	pdev = wlan_vdev_get_pdev(vdev);
280 	wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
281 	if (!wmi_handle) {
282 		coap_err("Invalid PDEV WMI handle");
283 		return QDF_STATUS_E_FAILURE;
284 	}
285 
286 	return wmi_unified_coap_cache_get(wmi_handle, wlan_vdev_get_id(vdev),
287 					  req_id);
288 }
289 
290 QDF_STATUS
target_if_coap_register_tx_ops(struct wlan_lmac_if_tx_ops * tx_ops)291 target_if_coap_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
292 {
293 	struct wlan_lmac_if_coap_tx_ops *coap_ops;
294 
295 	if (!tx_ops) {
296 		coap_err("target if tx ops is NULL!");
297 		return QDF_STATUS_E_INVAL;
298 	}
299 
300 	coap_ops = &tx_ops->coap_ops;
301 	coap_ops->attach = target_if_coap_register_event_handler;
302 	coap_ops->detach = target_if_coap_unregister_event_handler;
303 	coap_ops->offload_reply_enable =
304 		target_if_coap_offload_reply_enable;
305 	coap_ops->offload_reply_disable =
306 		target_if_coap_offload_reply_disable;
307 	coap_ops->offload_periodic_tx_enable =
308 		target_if_coap_offload_periodic_tx_enable;
309 	coap_ops->offload_periodic_tx_disable =
310 		target_if_coap_offload_periodic_tx_disable;
311 	coap_ops->offload_cache_get = target_if_coap_offload_cache_get;
312 
313 	return QDF_STATUS_SUCCESS;
314 }
315