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, ¶ms);
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, ¶ms);
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, ¶m);
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, ¶m);
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(¶ms);
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(¶ms);
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