wlan_cfg80211_coap.c 18 KB

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