xref: /wlan-driver/qcacld-3.0/os_if/coap/src/wlan_cfg80211_coap.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for any
5*5113495bSYour Name  * purpose with or without fee is hereby granted, provided that the above
6*5113495bSYour Name  * copyright notice and this permission notice appear in all copies.
7*5113495bSYour Name  *
8*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*5113495bSYour Name  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*5113495bSYour Name  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*5113495bSYour Name  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*5113495bSYour Name  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*5113495bSYour Name  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*5113495bSYour Name  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*5113495bSYour Name  */
16*5113495bSYour Name 
17*5113495bSYour Name /**
18*5113495bSYour Name  * DOC: defines driver functions interfacing with linux kernel
19*5113495bSYour Name  */
20*5113495bSYour Name #include <wmi_unified_param.h>
21*5113495bSYour Name #include <wlan_osif_request_manager.h>
22*5113495bSYour Name #include <osif_sync.h>
23*5113495bSYour Name #include <wlan_objmgr_psoc_obj.h>
24*5113495bSYour Name #include <wlan_hdd_main.h>
25*5113495bSYour Name #include <wlan_coap_main.h>
26*5113495bSYour Name #include <wlan_coap_ucfg_api.h>
27*5113495bSYour Name #include <wlan_cfg80211_coap.h>
28*5113495bSYour Name 
29*5113495bSYour Name #define COAP_MATCH_DATA_BYTES_MAX 16
30*5113495bSYour Name #define COAP_MSG_BYTES_MAX 1152
31*5113495bSYour Name #define COAP_OFFLOAD_REPLY_CACHE_EXPTIME_MS 40000
32*5113495bSYour Name #define COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS 2000
33*5113495bSYour Name 
34*5113495bSYour Name #define COAP_ATTR(_name) QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ ## _name
35*5113495bSYour Name 
36*5113495bSYour Name static const struct nla_policy
37*5113495bSYour Name coap_offload_filter_policy[COAP_ATTR(FILTER_MAX) + 1] = {
38*5113495bSYour Name 	[COAP_ATTR(FILTER_DEST_IPV4)] = {.type = NLA_U32},
39*5113495bSYour Name 	[COAP_ATTR(FILTER_DEST_IPV4_IS_BC)] = {.type = NLA_FLAG},
40*5113495bSYour Name 	[COAP_ATTR(FILTER_DEST_PORT)] = {.type = NLA_U16},
41*5113495bSYour Name 	[COAP_ATTR(FILTER_MATCH_OFFSET)] = {.type = NLA_U32},
42*5113495bSYour Name 	[COAP_ATTR(FILTER_MATCH_DATA)] = {
43*5113495bSYour Name 		.type = NLA_BINARY, .len = COAP_MATCH_DATA_BYTES_MAX},
44*5113495bSYour Name };
45*5113495bSYour Name 
46*5113495bSYour Name static const struct nla_policy
47*5113495bSYour Name coap_offload_tx_ipv4_policy[COAP_ATTR(TX_IPV4_MAX) + 1] = {
48*5113495bSYour Name 	[COAP_ATTR(TX_IPV4_SRC_ADDR)] = {.type = NLA_U32},
49*5113495bSYour Name 	[COAP_ATTR(TX_IPV4_SRC_PORT)] = {.type = NLA_U16},
50*5113495bSYour Name 	[COAP_ATTR(TX_IPV4_DEST_ADDR)] = {.type = NLA_U32},
51*5113495bSYour Name 	[COAP_ATTR(TX_IPV4_DEST_IS_BC)] = {.type = NLA_FLAG},
52*5113495bSYour Name 	[COAP_ATTR(TX_IPV4_DEST_PORT)] = {.type = NLA_U16},
53*5113495bSYour Name };
54*5113495bSYour Name 
55*5113495bSYour Name static const struct nla_policy
56*5113495bSYour Name coap_offload_reply_policy[COAP_ATTR(REPLY_MAX) + 1] = {
57*5113495bSYour Name 	[COAP_ATTR(REPLY_SRC_IPV4)] = {.type = NLA_U32},
58*5113495bSYour Name 	[COAP_ATTR(REPLY_FILTER)] =
59*5113495bSYour Name 		VENDOR_NLA_POLICY_NESTED(coap_offload_filter_policy),
60*5113495bSYour Name 	[COAP_ATTR(REPLY_MSG)] = {
61*5113495bSYour Name 		.type = NLA_BINARY, .len = COAP_MSG_BYTES_MAX},
62*5113495bSYour Name 	[COAP_ATTR(REPLY_CACHE_EXPTIME)] = {.type = NLA_U32},
63*5113495bSYour Name };
64*5113495bSYour Name 
65*5113495bSYour Name static const struct nla_policy
66*5113495bSYour Name coap_offload_periodic_tx_policy[COAP_ATTR(PERIODIC_TX_MAX) + 1] = {
67*5113495bSYour Name 	[COAP_ATTR(PERIODIC_TX_IPV4)] =
68*5113495bSYour Name 		VENDOR_NLA_POLICY_NESTED(coap_offload_tx_ipv4_policy),
69*5113495bSYour Name 	[COAP_ATTR(PERIODIC_TX_PERIOD)] = {.type = NLA_U32},
70*5113495bSYour Name 	[COAP_ATTR(PERIODIC_TX_MSG)] = {
71*5113495bSYour Name 		.type = NLA_BINARY, .len = COAP_MSG_BYTES_MAX},
72*5113495bSYour Name };
73*5113495bSYour Name 
74*5113495bSYour Name const struct nla_policy
75*5113495bSYour Name coap_offload_policy[COAP_ATTR(MAX) + 1] = {
76*5113495bSYour Name 	[COAP_ATTR(ACTION)] = {.type = NLA_U32 },
77*5113495bSYour Name 	[COAP_ATTR(REQ_ID)] = {.type = NLA_U32 },
78*5113495bSYour Name 	[COAP_ATTR(REPLY)] =
79*5113495bSYour Name 		VENDOR_NLA_POLICY_NESTED(coap_offload_reply_policy),
80*5113495bSYour Name 	[COAP_ATTR(PERIODIC_TX)] =
81*5113495bSYour Name 		VENDOR_NLA_POLICY_NESTED(coap_offload_periodic_tx_policy),
82*5113495bSYour Name };
83*5113495bSYour Name 
84*5113495bSYour Name /**
85*5113495bSYour Name  * wlan_cfg80211_coap_offload_reply_fill_filter() - fill filter for CoAP
86*5113495bSYour Name  * offload reply.
87*5113495bSYour Name  * @attr_filter: pointer to filter attribute
88*5113495bSYour Name  * @params: pointer to parameters for CoAP offload reply
89*5113495bSYour Name  *
90*5113495bSYour Name  * Return: 0 on success; error number otherwise
91*5113495bSYour Name  */
92*5113495bSYour Name static int
wlan_cfg80211_coap_offload_reply_fill_filter(struct nlattr * attr_filter,struct coap_offload_reply_param * params)93*5113495bSYour Name wlan_cfg80211_coap_offload_reply_fill_filter(struct nlattr *attr_filter,
94*5113495bSYour Name 	struct coap_offload_reply_param *params)
95*5113495bSYour Name {
96*5113495bSYour Name 	struct nlattr *tb[COAP_ATTR(FILTER_MAX) + 1];
97*5113495bSYour Name 
98*5113495bSYour Name 	if (!attr_filter) {
99*5113495bSYour Name 		coap_err("No ATTR filter");
100*5113495bSYour Name 		return -EINVAL;
101*5113495bSYour Name 	}
102*5113495bSYour Name 
103*5113495bSYour Name 	if (!nla_data(attr_filter)) {
104*5113495bSYour Name 		coap_err("Invalid filter");
105*5113495bSYour Name 		return -EINVAL;
106*5113495bSYour Name 	}
107*5113495bSYour Name 
108*5113495bSYour Name 	if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(FILTER_MAX),
109*5113495bSYour Name 					   attr_filter,
110*5113495bSYour Name 					   coap_offload_filter_policy)) {
111*5113495bSYour Name 		coap_err("Invalid ATTR");
112*5113495bSYour Name 		return -EINVAL;
113*5113495bSYour Name 	}
114*5113495bSYour Name 
115*5113495bSYour Name 	if (!tb[COAP_ATTR(FILTER_DEST_IPV4)]) {
116*5113495bSYour Name 		coap_err("no ATTR dest IPv4");
117*5113495bSYour Name 		return -EINVAL;
118*5113495bSYour Name 	}
119*5113495bSYour Name 
120*5113495bSYour Name 	params->dest_ip_v4 = nla_get_u32(tb[COAP_ATTR(FILTER_DEST_IPV4)]);
121*5113495bSYour Name 	params->dest_ip_v4_is_bc =
122*5113495bSYour Name 		nla_get_flag(tb[COAP_ATTR(FILTER_DEST_IPV4_IS_BC)]);
123*5113495bSYour Name 
124*5113495bSYour Name 	if (!tb[COAP_ATTR(FILTER_DEST_PORT)]) {
125*5113495bSYour Name 		coap_err("no ATTR dest IPv4 port");
126*5113495bSYour Name 		return -EINVAL;
127*5113495bSYour Name 	}
128*5113495bSYour Name 
129*5113495bSYour Name 	params->dest_udp_port = nla_get_u16(tb[COAP_ATTR(FILTER_DEST_PORT)]);
130*5113495bSYour Name 
131*5113495bSYour Name 	if (!tb[COAP_ATTR(FILTER_MATCH_OFFSET)]) {
132*5113495bSYour Name 		coap_err("no ATTR match offset");
133*5113495bSYour Name 		return -EINVAL;
134*5113495bSYour Name 	}
135*5113495bSYour Name 
136*5113495bSYour Name 	params->verify_offset =
137*5113495bSYour Name 		nla_get_u32(tb[COAP_ATTR(FILTER_MATCH_OFFSET)]);
138*5113495bSYour Name 
139*5113495bSYour Name 	if (!tb[COAP_ATTR(FILTER_MATCH_DATA)]) {
140*5113495bSYour Name 		coap_err("no ATTR match data");
141*5113495bSYour Name 		return -EINVAL;
142*5113495bSYour Name 	}
143*5113495bSYour Name 
144*5113495bSYour Name 	params->verify_len = nla_len(tb[COAP_ATTR(FILTER_MATCH_DATA)]);
145*5113495bSYour Name 	if (!params->verify_len) {
146*5113495bSYour Name 		coap_err("invalid match data len");
147*5113495bSYour Name 		return -EINVAL;
148*5113495bSYour Name 	}
149*5113495bSYour Name 
150*5113495bSYour Name 	params->verify = nla_data(tb[COAP_ATTR(FILTER_MATCH_DATA)]);
151*5113495bSYour Name 	return 0;
152*5113495bSYour Name }
153*5113495bSYour Name 
154*5113495bSYour Name /**
155*5113495bSYour Name  * wlan_cfg80211_coap_offload_reply_enable() - enable CoAP offload reply
156*5113495bSYour Name  * @vdev: pointer to vdev object
157*5113495bSYour Name  * @req_id: request id
158*5113495bSYour Name  * @attr_reply: pointer to CoAP offload reply attribute
159*5113495bSYour Name  *
160*5113495bSYour Name  * Return: 0 on success; error number otherwise
161*5113495bSYour Name  */
162*5113495bSYour Name static int
wlan_cfg80211_coap_offload_reply_enable(struct wlan_objmgr_vdev * vdev,uint32_t req_id,struct nlattr * attr_reply)163*5113495bSYour Name wlan_cfg80211_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev,
164*5113495bSYour Name 					uint32_t req_id,
165*5113495bSYour Name 					struct nlattr *attr_reply)
166*5113495bSYour Name {
167*5113495bSYour Name 	struct nlattr *tb[COAP_ATTR(REPLY_MAX) + 1];
168*5113495bSYour Name 	struct coap_offload_reply_param params = {0};
169*5113495bSYour Name 	struct nlattr *attr;
170*5113495bSYour Name 	QDF_STATUS status;
171*5113495bSYour Name 	int ret;
172*5113495bSYour Name 
173*5113495bSYour Name 	if (!attr_reply) {
174*5113495bSYour Name 		coap_err("No ATTR reply");
175*5113495bSYour Name 		return -EINVAL;
176*5113495bSYour Name 	}
177*5113495bSYour Name 
178*5113495bSYour Name 	if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(REPLY_MAX),
179*5113495bSYour Name 					   attr_reply,
180*5113495bSYour Name 					   coap_offload_reply_policy)) {
181*5113495bSYour Name 		coap_err("Invalid ATTR");
182*5113495bSYour Name 		return -EINVAL;
183*5113495bSYour Name 	}
184*5113495bSYour Name 
185*5113495bSYour Name 	attr = tb[COAP_ATTR(REPLY_SRC_IPV4)];
186*5113495bSYour Name 	if (!attr) {
187*5113495bSYour Name 		coap_err("No ATTR IPv4");
188*5113495bSYour Name 		return -EINVAL;
189*5113495bSYour Name 	}
190*5113495bSYour Name 
191*5113495bSYour Name 	params.pattern_id = req_id;
192*5113495bSYour Name 	params.vdev_id = wlan_vdev_get_id(vdev);
193*5113495bSYour Name 	params.src_ip_v4 = nla_get_u32(attr);
194*5113495bSYour Name 
195*5113495bSYour Name 	attr = tb[COAP_ATTR(REPLY_FILTER)];
196*5113495bSYour Name 	ret = wlan_cfg80211_coap_offload_reply_fill_filter(attr, &params);
197*5113495bSYour Name 	if (ret)
198*5113495bSYour Name 		return ret;
199*5113495bSYour Name 
200*5113495bSYour Name 	attr = tb[COAP_ATTR(REPLY_MSG)];
201*5113495bSYour Name 	if (!attr) {
202*5113495bSYour Name 		coap_err("No ATTR msg");
203*5113495bSYour Name 		return -EINVAL;
204*5113495bSYour Name 	}
205*5113495bSYour Name 
206*5113495bSYour Name 	params.coapmsg_len = nla_len(attr);
207*5113495bSYour Name 	params.coapmsg = nla_data(attr);
208*5113495bSYour Name 
209*5113495bSYour Name 	attr = tb[COAP_ATTR(REPLY_CACHE_EXPTIME)];
210*5113495bSYour Name 	if (!attr)
211*5113495bSYour Name 		params.cache_timeout = COAP_OFFLOAD_REPLY_CACHE_EXPTIME_MS;
212*5113495bSYour Name 	else
213*5113495bSYour Name 		params.cache_timeout = nla_get_u32(attr);
214*5113495bSYour Name 
215*5113495bSYour Name 	status = ucfg_coap_offload_reply_enable(vdev, &params);
216*5113495bSYour Name 	ret = qdf_status_to_os_return(status);
217*5113495bSYour Name 	return ret;
218*5113495bSYour Name }
219*5113495bSYour Name 
220*5113495bSYour Name /**
221*5113495bSYour Name  * wlan_cfg80211_coap_offload_fill_tx_ipv4() - fill IPv4 source/destination
222*5113495bSYour Name  * address/port for offload transmitting.
223*5113495bSYour Name  * @attr_ipv4: pointer to TX IPv4 attribute
224*5113495bSYour Name  * @params: pointer to parameters for CoAP offload reply
225*5113495bSYour Name  *
226*5113495bSYour Name  * Return: 0 on success; error number otherwise
227*5113495bSYour Name  */
228*5113495bSYour Name static int
wlan_cfg80211_coap_offload_fill_tx_ipv4(struct nlattr * attr_ipv4,struct coap_offload_periodic_tx_param * params)229*5113495bSYour Name wlan_cfg80211_coap_offload_fill_tx_ipv4(struct nlattr *attr_ipv4,
230*5113495bSYour Name 			struct coap_offload_periodic_tx_param *params)
231*5113495bSYour Name {
232*5113495bSYour Name 	struct nlattr *tb[COAP_ATTR(TX_IPV4_MAX) + 1];
233*5113495bSYour Name 
234*5113495bSYour Name 	if (!attr_ipv4) {
235*5113495bSYour Name 		coap_err("No ATTR TX IPv4");
236*5113495bSYour Name 		return -EINVAL;
237*5113495bSYour Name 	}
238*5113495bSYour Name 
239*5113495bSYour Name 	if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(TX_IPV4_MAX),
240*5113495bSYour Name 					   attr_ipv4,
241*5113495bSYour Name 					   coap_offload_tx_ipv4_policy)) {
242*5113495bSYour Name 		coap_err("Invalid ATTR");
243*5113495bSYour Name 		return -EINVAL;
244*5113495bSYour Name 	}
245*5113495bSYour Name 
246*5113495bSYour Name 	if (!tb[COAP_ATTR(TX_IPV4_SRC_ADDR)]) {
247*5113495bSYour Name 		coap_err("no ATTR src addr");
248*5113495bSYour Name 		return -EINVAL;
249*5113495bSYour Name 	}
250*5113495bSYour Name 
251*5113495bSYour Name 	params->src_ip_v4 = nla_get_u32(tb[COAP_ATTR(TX_IPV4_SRC_ADDR)]);
252*5113495bSYour Name 	if (tb[COAP_ATTR(TX_IPV4_SRC_PORT)])
253*5113495bSYour Name 		params->src_udp_port =
254*5113495bSYour Name 			nla_get_u32(tb[COAP_ATTR(TX_IPV4_SRC_PORT)]);
255*5113495bSYour Name 
256*5113495bSYour Name 	if (!tb[COAP_ATTR(TX_IPV4_DEST_ADDR)]) {
257*5113495bSYour Name 		coap_err("no ATTR IPv4 dest addr");
258*5113495bSYour Name 		return -EINVAL;
259*5113495bSYour Name 	}
260*5113495bSYour Name 
261*5113495bSYour Name 	params->dest_ip_v4 = nla_get_u32(tb[COAP_ATTR(TX_IPV4_DEST_ADDR)]);
262*5113495bSYour Name 	params->dest_ip_v4_is_bc =
263*5113495bSYour Name 		nla_get_flag(tb[COAP_ATTR(TX_IPV4_DEST_IS_BC)]);
264*5113495bSYour Name 
265*5113495bSYour Name 	if (!tb[COAP_ATTR(TX_IPV4_DEST_PORT)]) {
266*5113495bSYour Name 		coap_err("no ATTR dest IPv4 port");
267*5113495bSYour Name 		return -EINVAL;
268*5113495bSYour Name 	}
269*5113495bSYour Name 
270*5113495bSYour Name 	params->dest_udp_port =
271*5113495bSYour Name 		nla_get_u32(tb[COAP_ATTR(TX_IPV4_DEST_PORT)]);
272*5113495bSYour Name 	return 0;
273*5113495bSYour Name }
274*5113495bSYour Name 
275*5113495bSYour Name /**
276*5113495bSYour Name  * wlan_cfg80211_coap_offload_periodic_tx_enable() - enable CoAP offload
277*5113495bSYour Name  * periodic transmitting
278*5113495bSYour Name  * @vdev: pointer to vdev object
279*5113495bSYour Name  * @req_id: request id
280*5113495bSYour Name  * @attr_periodic_tx: pointer to CoAP offload periodic TX attribute
281*5113495bSYour Name  *
282*5113495bSYour Name  * Return: 0 on success; error number otherwise
283*5113495bSYour Name  */
284*5113495bSYour Name static int
wlan_cfg80211_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev * vdev,uint32_t req_id,struct nlattr * attr_periodic_tx)285*5113495bSYour Name wlan_cfg80211_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev,
286*5113495bSYour Name 					      uint32_t req_id,
287*5113495bSYour Name 					      struct nlattr *attr_periodic_tx)
288*5113495bSYour Name {
289*5113495bSYour Name 	struct nlattr *tb[COAP_ATTR(PERIODIC_TX_MAX) + 1];
290*5113495bSYour Name 	struct coap_offload_periodic_tx_param param = {0};
291*5113495bSYour Name 	struct nlattr *attr_ipv4;
292*5113495bSYour Name 	QDF_STATUS status;
293*5113495bSYour Name 	int ret;
294*5113495bSYour Name 
295*5113495bSYour Name 	if (!attr_periodic_tx) {
296*5113495bSYour Name 		coap_err("No ATTR periodic tx");
297*5113495bSYour Name 		return -EINVAL;
298*5113495bSYour Name 	}
299*5113495bSYour Name 
300*5113495bSYour Name 	if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(PERIODIC_TX_MAX),
301*5113495bSYour Name 					   attr_periodic_tx,
302*5113495bSYour Name 					   coap_offload_periodic_tx_policy)) {
303*5113495bSYour Name 		coap_err("Invalid ATTR");
304*5113495bSYour Name 		return -EINVAL;
305*5113495bSYour Name 	}
306*5113495bSYour Name 
307*5113495bSYour Name 	if (!tb[COAP_ATTR(PERIODIC_TX_PERIOD)]) {
308*5113495bSYour Name 		coap_err("no ATTR period");
309*5113495bSYour Name 		return -EINVAL;
310*5113495bSYour Name 	}
311*5113495bSYour Name 
312*5113495bSYour Name 	param.timeout = nla_get_u32(tb[COAP_ATTR(PERIODIC_TX_PERIOD)]);
313*5113495bSYour Name 	attr_ipv4 = tb[COAP_ATTR(PERIODIC_TX_IPV4)];
314*5113495bSYour Name 	ret = wlan_cfg80211_coap_offload_fill_tx_ipv4(attr_ipv4, &param);
315*5113495bSYour Name 	if (ret)
316*5113495bSYour Name 		return ret;
317*5113495bSYour Name 
318*5113495bSYour Name 	param.vdev_id = wlan_vdev_get_id(vdev);
319*5113495bSYour Name 	param.pattern_id = req_id;
320*5113495bSYour Name 	if (!tb[COAP_ATTR(PERIODIC_TX_MSG)]) {
321*5113495bSYour Name 		coap_err("no ATTR msg");
322*5113495bSYour Name 		return -EINVAL;
323*5113495bSYour Name 	}
324*5113495bSYour Name 
325*5113495bSYour Name 	param.coapmsg_len = nla_len(tb[COAP_ATTR(PERIODIC_TX_MSG)]);
326*5113495bSYour Name 	param.coapmsg = nla_data(tb[COAP_ATTR(PERIODIC_TX_MSG)]);
327*5113495bSYour Name 	status = ucfg_coap_offload_periodic_tx_enable(vdev, &param);
328*5113495bSYour Name 	return qdf_status_to_os_return(status);
329*5113495bSYour Name }
330*5113495bSYour Name 
331*5113495bSYour Name /**
332*5113495bSYour Name  * wlan_cfg80211_coap_offload_periodic_tx_disable() - disable CoAP offload
333*5113495bSYour Name  * periodic transmitting
334*5113495bSYour Name  * @vdev: pointer to vdev object
335*5113495bSYour Name  * @req_id: request id
336*5113495bSYour Name  *
337*5113495bSYour Name  * Return: 0 on success; error number otherwise
338*5113495bSYour Name  */
339*5113495bSYour Name static int
wlan_cfg80211_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev * vdev,uint32_t req_id)340*5113495bSYour Name wlan_cfg80211_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev,
341*5113495bSYour Name 					       uint32_t req_id)
342*5113495bSYour Name {
343*5113495bSYour Name 	QDF_STATUS status;
344*5113495bSYour Name 
345*5113495bSYour Name 	status = ucfg_coap_offload_periodic_tx_disable(vdev, req_id);
346*5113495bSYour Name 	return qdf_status_to_os_return(status);
347*5113495bSYour Name }
348*5113495bSYour Name 
349*5113495bSYour Name /**
350*5113495bSYour Name  * wlan_cfg80211_dealloc_coap_buf_info() - Callback to free priv
351*5113495bSYour Name  * allocations for CoAP buffer info
352*5113495bSYour Name  * @priv: Pointer to priv data statucture
353*5113495bSYour Name  *
354*5113495bSYour Name  * Return: None
355*5113495bSYour Name  */
wlan_cfg80211_dealloc_coap_buf_info(void * priv)356*5113495bSYour Name static void wlan_cfg80211_dealloc_coap_buf_info(void *priv)
357*5113495bSYour Name {
358*5113495bSYour Name 	struct coap_buf_info *info = priv;
359*5113495bSYour Name 	struct coap_buf_node *cur, *next;
360*5113495bSYour Name 
361*5113495bSYour Name 	if (!info)
362*5113495bSYour Name 		return;
363*5113495bSYour Name 
364*5113495bSYour Name 	qdf_list_for_each_del(&info->info_list, cur, next, node) {
365*5113495bSYour Name 		qdf_list_remove_node(&info->info_list, &cur->node);
366*5113495bSYour Name 		qdf_mem_free(cur->payload);
367*5113495bSYour Name 		qdf_mem_free(cur);
368*5113495bSYour Name 	}
369*5113495bSYour Name 
370*5113495bSYour Name 	qdf_list_destroy(&info->info_list);
371*5113495bSYour Name }
372*5113495bSYour Name 
373*5113495bSYour Name static void
wlan_cfg80211_coap_cache_get_cbk(void * context,struct coap_buf_info * info)374*5113495bSYour Name wlan_cfg80211_coap_cache_get_cbk(void *context, struct coap_buf_info *info)
375*5113495bSYour Name {
376*5113495bSYour Name 	struct osif_request *request;
377*5113495bSYour Name 	struct coap_buf_info *priv_info;
378*5113495bSYour Name 
379*5113495bSYour Name 	if (!context || !info)
380*5113495bSYour Name 		return;
381*5113495bSYour Name 
382*5113495bSYour Name 	request = osif_request_get(context);
383*5113495bSYour Name 	if (!request)
384*5113495bSYour Name 		return;
385*5113495bSYour Name 
386*5113495bSYour Name 	priv_info = osif_request_priv(request);
387*5113495bSYour Name 	if (info->req_id == priv_info->req_id) {
388*5113495bSYour Name 		qdf_list_join(&priv_info->info_list, &info->info_list);
389*5113495bSYour Name 		if (!info->more_info)
390*5113495bSYour Name 			osif_request_complete(request);
391*5113495bSYour Name 	}
392*5113495bSYour Name 
393*5113495bSYour Name 	osif_request_put(request);
394*5113495bSYour Name }
395*5113495bSYour Name 
396*5113495bSYour Name /**
397*5113495bSYour Name  * wlan_cfg80211_coap_fill_buf_info() - Fill cache get response buffer
398*5113495bSYour Name  * @reply_skb : pointer to reply_skb
399*5113495bSYour Name  * @info : information of cached CoAP messages
400*5113495bSYour Name  * @index : attribute type index for nla_next_start()
401*5113495bSYour Name  *
402*5113495bSYour Name  * Return : 0 on success and errno on failure
403*5113495bSYour Name  */
404*5113495bSYour Name static int
wlan_cfg80211_coap_fill_buf_info(struct sk_buff * reply_skb,struct coap_buf_node * info,int index)405*5113495bSYour Name wlan_cfg80211_coap_fill_buf_info(struct sk_buff *reply_skb,
406*5113495bSYour Name 				 struct coap_buf_node *info, int index)
407*5113495bSYour Name {
408*5113495bSYour Name 	struct nlattr *attr;
409*5113495bSYour Name 
410*5113495bSYour Name 	attr = nla_nest_start(reply_skb, index);
411*5113495bSYour Name 	if (!attr) {
412*5113495bSYour Name 		coap_err("nla_nest_start failed");
413*5113495bSYour Name 		return -EINVAL;
414*5113495bSYour Name 	}
415*5113495bSYour Name 
416*5113495bSYour Name 	if (hdd_wlan_nla_put_u64(reply_skb, COAP_ATTR(CACHE_INFO_TS),
417*5113495bSYour Name 				 info->tsf) ||
418*5113495bSYour Name 	    nla_put_u32(reply_skb, COAP_ATTR(CACHE_INFO_SRC_IPV4),
419*5113495bSYour Name 			info->src_ip) ||
420*5113495bSYour Name 	    nla_put(reply_skb, COAP_ATTR(CACHE_INFO_MSG),
421*5113495bSYour Name 		    info->len, info->payload)) {
422*5113495bSYour Name 		coap_err("nla_put failed");
423*5113495bSYour Name 		return -EINVAL;
424*5113495bSYour Name 	}
425*5113495bSYour Name 
426*5113495bSYour Name 	nla_nest_end(reply_skb, attr);
427*5113495bSYour Name 	return 0;
428*5113495bSYour Name }
429*5113495bSYour Name 
430*5113495bSYour Name /**
431*5113495bSYour Name  * wlan_cfg80211_coap_offload_cache_deliver() - deliver cached CoAP messages
432*5113495bSYour Name  * @wiphy: pointer to wireless wiphy structure.
433*5113495bSYour Name  * @cache_list: list of cached CoAP messages
434*5113495bSYour Name  *
435*5113495bSYour Name  * Return: 0 on success; error number otherwise
436*5113495bSYour Name  */
437*5113495bSYour Name static int
wlan_cfg80211_coap_offload_cache_deliver(struct wiphy * wiphy,qdf_list_t * cache_list)438*5113495bSYour Name wlan_cfg80211_coap_offload_cache_deliver(struct wiphy *wiphy,
439*5113495bSYour Name 					 qdf_list_t *cache_list)
440*5113495bSYour Name {
441*5113495bSYour Name 	struct sk_buff *skb;
442*5113495bSYour Name 	uint32_t skb_len = NLMSG_HDRLEN;
443*5113495bSYour Name 	struct coap_buf_node *cur, *next;
444*5113495bSYour Name 	struct nlattr *attr;
445*5113495bSYour Name 	int i = 0, ret;
446*5113495bSYour Name 
447*5113495bSYour Name 	/* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES */
448*5113495bSYour Name 	skb_len += nla_total_size(0);
449*5113495bSYour Name 	qdf_list_for_each_del(cache_list, cur, next, node) {
450*5113495bSYour Name 		if (!cur->len || !cur->payload)
451*5113495bSYour Name 			continue;
452*5113495bSYour Name 
453*5113495bSYour Name 		/* nest attribute */
454*5113495bSYour Name 		skb_len += nla_total_size(0);
455*5113495bSYour Name 
456*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_TS */
457*5113495bSYour Name 		skb_len += nla_total_size(sizeof(uint64_t));
458*5113495bSYour Name 
459*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4 */
460*5113495bSYour Name 		skb_len += nla_total_size(sizeof(uint32_t));
461*5113495bSYour Name 
462*5113495bSYour Name 		/* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MSG */
463*5113495bSYour Name 		skb_len += nla_total_size(cur->len);
464*5113495bSYour Name 	}
465*5113495bSYour Name 
466*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
467*5113495bSYour Name 	attr = nla_nest_start(skb, COAP_ATTR(CACHES));
468*5113495bSYour Name 	if (!attr) {
469*5113495bSYour Name 		hdd_err("nla_nest_start failed");
470*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(skb);
471*5113495bSYour Name 		return -EINVAL;
472*5113495bSYour Name 	}
473*5113495bSYour Name 
474*5113495bSYour Name 	qdf_list_for_each_del(cache_list, cur, next, node) {
475*5113495bSYour Name 		if (!cur->len || !cur->payload)
476*5113495bSYour Name 			continue;
477*5113495bSYour Name 
478*5113495bSYour Name 		qdf_list_remove_node(cache_list, &cur->node);
479*5113495bSYour Name 		ret = wlan_cfg80211_coap_fill_buf_info(skb, cur, i++);
480*5113495bSYour Name 		if (ret) {
481*5113495bSYour Name 			wlan_cfg80211_vendor_free_skb(skb);
482*5113495bSYour Name 			return -EINVAL;
483*5113495bSYour Name 		}
484*5113495bSYour Name 
485*5113495bSYour Name 		qdf_mem_free(cur->payload);
486*5113495bSYour Name 		qdf_mem_free(cur);
487*5113495bSYour Name 	}
488*5113495bSYour Name 
489*5113495bSYour Name 	nla_nest_end(skb, attr);
490*5113495bSYour Name 	return wlan_cfg80211_vendor_cmd_reply(skb);
491*5113495bSYour Name }
492*5113495bSYour Name 
493*5113495bSYour Name /**
494*5113495bSYour Name  * wlan_cfg80211_coap_offload_cache_get() - get cached CoAP messages
495*5113495bSYour Name  * @wiphy: pointer to wireless wiphy structure.
496*5113495bSYour Name  * @vdev: pointer to vdev object
497*5113495bSYour Name  * @req_id: request id
498*5113495bSYour Name  *
499*5113495bSYour Name  * Return: 0 on success; error number otherwise
500*5113495bSYour Name  */
501*5113495bSYour Name static int
wlan_cfg80211_coap_offload_cache_get(struct wiphy * wiphy,struct wlan_objmgr_vdev * vdev,uint32_t req_id)502*5113495bSYour Name wlan_cfg80211_coap_offload_cache_get(struct wiphy *wiphy,
503*5113495bSYour Name 				     struct wlan_objmgr_vdev *vdev,
504*5113495bSYour Name 				     uint32_t req_id)
505*5113495bSYour Name {
506*5113495bSYour Name 	void *cookie;
507*5113495bSYour Name 	QDF_STATUS status;
508*5113495bSYour Name 	struct osif_request *request;
509*5113495bSYour Name 	struct coap_buf_info *buf_info;
510*5113495bSYour Name 	int ret;
511*5113495bSYour Name 	static const struct osif_request_params params = {
512*5113495bSYour Name 		.priv_size = sizeof(*buf_info),
513*5113495bSYour Name 		.timeout_ms = COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS,
514*5113495bSYour Name 		.dealloc = wlan_cfg80211_dealloc_coap_buf_info,
515*5113495bSYour Name 	};
516*5113495bSYour Name 
517*5113495bSYour Name 	request = osif_request_alloc(&params);
518*5113495bSYour Name 	if (!request) {
519*5113495bSYour Name 		coap_err("Request allocation failure");
520*5113495bSYour Name 		status = QDF_STATUS_E_NOMEM;
521*5113495bSYour Name 		goto out;
522*5113495bSYour Name 	}
523*5113495bSYour Name 
524*5113495bSYour Name 	buf_info = osif_request_priv(request);
525*5113495bSYour Name 	qdf_list_create(&buf_info->info_list, 0);
526*5113495bSYour Name 	buf_info->req_id = req_id;
527*5113495bSYour Name 	buf_info->vdev_id = wlan_vdev_get_id(vdev);
528*5113495bSYour Name 
529*5113495bSYour Name 	cookie = osif_request_cookie(request);
530*5113495bSYour Name 	status = ucfg_coap_offload_cache_get(vdev, req_id,
531*5113495bSYour Name 					     wlan_cfg80211_coap_cache_get_cbk,
532*5113495bSYour Name 					     cookie);
533*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
534*5113495bSYour Name 		coap_err("Unable to get cache");
535*5113495bSYour Name 		goto out;
536*5113495bSYour Name 	}
537*5113495bSYour Name 
538*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
539*5113495bSYour Name 	if (ret) {
540*5113495bSYour Name 		coap_err("Target response timed out");
541*5113495bSYour Name 		status = qdf_status_from_os_return(ret);
542*5113495bSYour Name 		goto out;
543*5113495bSYour Name 	}
544*5113495bSYour Name 
545*5113495bSYour Name 	ret = wlan_cfg80211_coap_offload_cache_deliver(wiphy,
546*5113495bSYour Name 						       &buf_info->info_list);
547*5113495bSYour Name 	if (ret) {
548*5113495bSYour Name 		coap_err("Failed to deliver buf info");
549*5113495bSYour Name 		status = qdf_status_from_os_return(ret);
550*5113495bSYour Name 		goto out;
551*5113495bSYour Name 	}
552*5113495bSYour Name 
553*5113495bSYour Name out:
554*5113495bSYour Name 	if (request)
555*5113495bSYour Name 		osif_request_put(request);
556*5113495bSYour Name 	return qdf_status_to_os_return(status);
557*5113495bSYour Name }
558*5113495bSYour Name 
559*5113495bSYour Name /**
560*5113495bSYour Name  * wlan_cfg80211_coap_offload_reply_disable() - disable CoAP offload reply
561*5113495bSYour Name  * @wiphy: pointer to wireless wiphy structure.
562*5113495bSYour Name  * @vdev: pointer to vdev object
563*5113495bSYour Name  * @req_id: request id
564*5113495bSYour Name  *
565*5113495bSYour Name  * Return: 0 on success; error number otherwise
566*5113495bSYour Name  */
567*5113495bSYour Name static int
wlan_cfg80211_coap_offload_reply_disable(struct wiphy * wiphy,struct wlan_objmgr_vdev * vdev,uint32_t req_id)568*5113495bSYour Name wlan_cfg80211_coap_offload_reply_disable(struct wiphy *wiphy,
569*5113495bSYour Name 					 struct wlan_objmgr_vdev *vdev,
570*5113495bSYour Name 					 uint32_t req_id)
571*5113495bSYour Name {
572*5113495bSYour Name 	void *cookie;
573*5113495bSYour Name 	QDF_STATUS status;
574*5113495bSYour Name 	struct osif_request *request;
575*5113495bSYour Name 	struct coap_buf_info *buf_info;
576*5113495bSYour Name 	int ret;
577*5113495bSYour Name 	static const struct osif_request_params params = {
578*5113495bSYour Name 		.priv_size = sizeof(*buf_info),
579*5113495bSYour Name 		.timeout_ms = COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS,
580*5113495bSYour Name 		.dealloc = wlan_cfg80211_dealloc_coap_buf_info,
581*5113495bSYour Name 	};
582*5113495bSYour Name 
583*5113495bSYour Name 	request = osif_request_alloc(&params);
584*5113495bSYour Name 	if (!request) {
585*5113495bSYour Name 		coap_err("Request allocation failure");
586*5113495bSYour Name 		status = QDF_STATUS_E_NOMEM;
587*5113495bSYour Name 		goto out;
588*5113495bSYour Name 	}
589*5113495bSYour Name 
590*5113495bSYour Name 	buf_info = osif_request_priv(request);
591*5113495bSYour Name 	qdf_list_create(&buf_info->info_list, 0);
592*5113495bSYour Name 	buf_info->req_id = req_id;
593*5113495bSYour Name 	buf_info->vdev_id = wlan_vdev_get_id(vdev);
594*5113495bSYour Name 
595*5113495bSYour Name 	cookie = osif_request_cookie(request);
596*5113495bSYour Name 	status = ucfg_coap_offload_reply_disable(vdev, req_id,
597*5113495bSYour Name 			wlan_cfg80211_coap_cache_get_cbk, cookie);
598*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
599*5113495bSYour Name 		coap_err("Failed to disable offload reply");
600*5113495bSYour Name 		goto out;
601*5113495bSYour Name 	}
602*5113495bSYour Name 
603*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
604*5113495bSYour Name 	if (ret) {
605*5113495bSYour Name 		coap_err("Target response timed out");
606*5113495bSYour Name 		status = qdf_status_from_os_return(ret);
607*5113495bSYour Name 		goto out;
608*5113495bSYour Name 	}
609*5113495bSYour Name 
610*5113495bSYour Name 	ret = wlan_cfg80211_coap_offload_cache_deliver(wiphy,
611*5113495bSYour Name 						       &buf_info->info_list);
612*5113495bSYour Name 	if (ret) {
613*5113495bSYour Name 		coap_err("Failed to deliver buf info");
614*5113495bSYour Name 		status = qdf_status_from_os_return(ret);
615*5113495bSYour Name 		goto out;
616*5113495bSYour Name 	}
617*5113495bSYour Name 
618*5113495bSYour Name out:
619*5113495bSYour Name 	if (request)
620*5113495bSYour Name 		osif_request_put(request);
621*5113495bSYour Name 	return qdf_status_to_os_return(status);
622*5113495bSYour Name }
623*5113495bSYour Name 
624*5113495bSYour Name int
wlan_cfg80211_coap_offload(struct wiphy * wiphy,struct wlan_objmgr_vdev * vdev,const void * data,int data_len)625*5113495bSYour Name wlan_cfg80211_coap_offload(struct wiphy *wiphy, struct wlan_objmgr_vdev *vdev,
626*5113495bSYour Name 			   const void *data, int data_len)
627*5113495bSYour Name {
628*5113495bSYour Name 	struct nlattr *tb[COAP_ATTR(MAX) + 1];
629*5113495bSYour Name 	struct nlattr *attr;
630*5113495bSYour Name 	uint32_t action, req_id;
631*5113495bSYour Name 	int ret;
632*5113495bSYour Name 
633*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb, COAP_ATTR(MAX),
634*5113495bSYour Name 				    data, data_len, coap_offload_policy)) {
635*5113495bSYour Name 		coap_err("Invalid ATTR");
636*5113495bSYour Name 		return -EINVAL;
637*5113495bSYour Name 	}
638*5113495bSYour Name 
639*5113495bSYour Name 	if (!tb[COAP_ATTR(ACTION)]) {
640*5113495bSYour Name 		coap_err("no attr action");
641*5113495bSYour Name 		return -EINVAL;
642*5113495bSYour Name 	}
643*5113495bSYour Name 
644*5113495bSYour Name 	if (!tb[COAP_ATTR(REQ_ID)]) {
645*5113495bSYour Name 		coap_err("no attr req id");
646*5113495bSYour Name 		return -EINVAL;
647*5113495bSYour Name 	}
648*5113495bSYour Name 
649*5113495bSYour Name 	action = nla_get_u32(tb[COAP_ATTR(ACTION)]);
650*5113495bSYour Name 	req_id = nla_get_u32(tb[COAP_ATTR(REQ_ID)]);
651*5113495bSYour Name 	switch (action) {
652*5113495bSYour Name 	case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE:
653*5113495bSYour Name 		attr = tb[COAP_ATTR(REPLY)];
654*5113495bSYour Name 		ret = wlan_cfg80211_coap_offload_reply_enable(vdev, req_id,
655*5113495bSYour Name 							      attr);
656*5113495bSYour Name 		break;
657*5113495bSYour Name 	case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE:
658*5113495bSYour Name 		ret = wlan_cfg80211_coap_offload_reply_disable(wiphy, vdev,
659*5113495bSYour Name 							       req_id);
660*5113495bSYour Name 		break;
661*5113495bSYour Name 	case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE:
662*5113495bSYour Name 		attr = tb[COAP_ATTR(PERIODIC_TX)];
663*5113495bSYour Name 		ret = wlan_cfg80211_coap_offload_periodic_tx_enable(vdev,
664*5113495bSYour Name 								    req_id,
665*5113495bSYour Name 								    attr);
666*5113495bSYour Name 		break;
667*5113495bSYour Name 	case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_DISABLE:
668*5113495bSYour Name 		ret = wlan_cfg80211_coap_offload_periodic_tx_disable(vdev,
669*5113495bSYour Name 								     req_id);
670*5113495bSYour Name 		break;
671*5113495bSYour Name 	case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET:
672*5113495bSYour Name 		ret = wlan_cfg80211_coap_offload_cache_get(wiphy, vdev,
673*5113495bSYour Name 							   req_id);
674*5113495bSYour Name 		break;
675*5113495bSYour Name 	default:
676*5113495bSYour Name 		ret = -EINVAL;
677*5113495bSYour Name 		break;
678*5113495bSYour Name 	}
679*5113495bSYour Name 
680*5113495bSYour Name 	coap_debug("vdev_id %u action %u req id %u ret %d",
681*5113495bSYour Name 		   wlan_vdev_get_id(vdev), action, req_id, ret);
682*5113495bSYour Name 	return ret;
683*5113495bSYour Name }
684