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.src_ip_v4 = nla_get_u32(attr);
  166. attr = tb[COAP_ATTR(REPLY_FILTER)];
  167. ret = wlan_cfg80211_coap_offload_reply_fill_filter(attr, &params);
  168. if (ret)
  169. return ret;
  170. attr = tb[COAP_ATTR(REPLY_MSG)];
  171. if (!attr) {
  172. coap_err("No ATTR msg");
  173. return -EINVAL;
  174. }
  175. params.coapmsg_len = nla_len(attr);
  176. params.coapmsg = nla_data(attr);
  177. attr = tb[COAP_ATTR(REPLY_CACHE_EXPTIME)];
  178. if (!attr)
  179. params.cache_timeout = COAP_OFFLOAD_REPLY_CACHE_EXPTIME_MS;
  180. else
  181. params.cache_timeout = nla_get_u32(attr);
  182. status = ucfg_coap_offload_reply_enable(vdev, &params);
  183. ret = qdf_status_to_os_return(status);
  184. return ret;
  185. }
  186. /**
  187. * wlan_cfg80211_coap_offload_fill_tx_ipv4() - fill IPv4 source/destination
  188. * address/port for offload transmitting.
  189. * @attr_ipv4: pointer to TX IPv4 attribute
  190. * @params: pointer to parameters for CoAP offload reply
  191. *
  192. * Return: 0 on success; error number otherwise
  193. */
  194. static int
  195. wlan_cfg80211_coap_offload_fill_tx_ipv4(struct nlattr *attr_ipv4,
  196. struct coap_offload_periodic_tx_param *params)
  197. {
  198. struct nlattr *tb[COAP_ATTR(TX_IPV4_MAX) + 1];
  199. if (!attr_ipv4) {
  200. coap_err("No ATTR TX IPv4");
  201. return -EINVAL;
  202. }
  203. if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(TX_IPV4_MAX),
  204. attr_ipv4,
  205. coap_offload_tx_ipv4_policy)) {
  206. coap_err("Invalid ATTR");
  207. return -EINVAL;
  208. }
  209. if (!tb[COAP_ATTR(TX_IPV4_SRC_ADDR)]) {
  210. coap_err("no ATTR src addr");
  211. return -EINVAL;
  212. }
  213. params->src_ip_v4 = nla_get_u32(tb[COAP_ATTR(TX_IPV4_SRC_ADDR)]);
  214. if (tb[COAP_ATTR(TX_IPV4_SRC_PORT)])
  215. params->src_udp_port =
  216. nla_get_u32(tb[COAP_ATTR(TX_IPV4_SRC_PORT)]);
  217. if (!tb[COAP_ATTR(TX_IPV4_DEST_ADDR)]) {
  218. coap_err("no ATTR IPv4 dest addr");
  219. return -EINVAL;
  220. }
  221. params->dest_ip_v4 = nla_get_u32(tb[COAP_ATTR(TX_IPV4_DEST_ADDR)]);
  222. params->dest_ip_v4_is_bc =
  223. nla_get_flag(tb[COAP_ATTR(TX_IPV4_DEST_IS_BC)]);
  224. if (!tb[COAP_ATTR(TX_IPV4_DEST_PORT)]) {
  225. coap_err("no ATTR dest IPv4 port");
  226. return -EINVAL;
  227. }
  228. params->dest_udp_port =
  229. nla_get_u32(tb[COAP_ATTR(TX_IPV4_DEST_PORT)]);
  230. return 0;
  231. }
  232. /**
  233. * wlan_cfg80211_coap_offload_periodic_tx_enable() - enable CoAP offload
  234. * periodic transmitting
  235. * @vdev: pointer to vdev object
  236. * @req_id: request id
  237. * @attr_reply: pointer to CoAP offload periodic TX attribute
  238. *
  239. * Return: 0 on success; error number otherwise
  240. */
  241. static int
  242. wlan_cfg80211_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev,
  243. uint32_t req_id,
  244. struct nlattr *attr_periodic_tx)
  245. {
  246. struct nlattr *tb[COAP_ATTR(PERIODIC_TX_MAX) + 1];
  247. struct coap_offload_periodic_tx_param param = {0};
  248. struct nlattr *attr_ipv4;
  249. QDF_STATUS status;
  250. int ret;
  251. if (!attr_periodic_tx) {
  252. coap_err("No ATTR periodic tx");
  253. return -EINVAL;
  254. }
  255. if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(PERIODIC_TX_MAX),
  256. attr_periodic_tx,
  257. coap_offload_periodic_tx_policy)) {
  258. coap_err("Invalid ATTR");
  259. return -EINVAL;
  260. }
  261. if (!tb[COAP_ATTR(PERIODIC_TX_PERIOD)]) {
  262. coap_err("no ATTR period");
  263. return -EINVAL;
  264. }
  265. param.timeout = nla_get_u32(tb[COAP_ATTR(PERIODIC_TX_PERIOD)]);
  266. attr_ipv4 = tb[COAP_ATTR(PERIODIC_TX_IPV4)];
  267. ret = wlan_cfg80211_coap_offload_fill_tx_ipv4(attr_ipv4, &param);
  268. if (ret)
  269. return ret;
  270. param.vdev_id = wlan_vdev_get_id(vdev);
  271. param.pattern_id = req_id;
  272. if (!tb[COAP_ATTR(PERIODIC_TX_MSG)]) {
  273. coap_err("no ATTR msg");
  274. return -EINVAL;
  275. }
  276. param.coapmsg_len = nla_len(tb[COAP_ATTR(PERIODIC_TX_MSG)]);
  277. param.coapmsg = nla_data(tb[COAP_ATTR(PERIODIC_TX_MSG)]);
  278. status = ucfg_coap_offload_periodic_tx_enable(vdev, &param);
  279. return qdf_status_to_os_return(status);
  280. }
  281. /**
  282. * wlan_cfg80211_coap_offload_periodic_tx_enable() - disable CoAP offload
  283. * periodic transmitting
  284. * @vdev: pointer to vdev object
  285. * @req_id: request id
  286. *
  287. * Return: 0 on success; error number otherwise
  288. */
  289. static int
  290. wlan_cfg80211_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev,
  291. uint32_t req_id)
  292. {
  293. QDF_STATUS status;
  294. status = ucfg_coap_offload_periodic_tx_disable(vdev, req_id);
  295. return qdf_status_to_os_return(status);
  296. }
  297. /**
  298. * wlan_cfg80211_dealloc_coap_buf_info() - Callback to free priv
  299. * allocations for CoAP buffer info
  300. * @priv: Pointer to priv data statucture
  301. *
  302. * Return: None
  303. */
  304. static void wlan_cfg80211_dealloc_coap_buf_info(void *priv)
  305. {
  306. struct coap_buf_info *info = priv;
  307. struct coap_buf_node *cur, *next;
  308. if (!info)
  309. return;
  310. qdf_list_for_each_del(&info->info_list, cur, next, node) {
  311. qdf_list_remove_node(&info->info_list, &cur->node);
  312. qdf_mem_free(cur->payload);
  313. qdf_mem_free(cur);
  314. }
  315. qdf_list_destroy(&info->info_list);
  316. }
  317. static void
  318. wlan_cfg80211_coap_cache_get_cbk(void *context, struct coap_buf_info *info)
  319. {
  320. struct osif_request *request;
  321. struct coap_buf_info *priv_info;
  322. if (!context || !info)
  323. return;
  324. request = osif_request_get(context);
  325. if (!request)
  326. return;
  327. priv_info = osif_request_priv(request);
  328. if (info->req_id != priv_info->req_id)
  329. return;
  330. qdf_list_join(&priv_info->info_list, &info->info_list);
  331. if (info->more_info)
  332. return;
  333. osif_request_complete(request);
  334. osif_request_put(request);
  335. }
  336. /**
  337. * wlan_cfg80211_coap_fill_buf_info() - Fill cache get response buffer
  338. * @reply_skb : pointer to reply_skb
  339. * @info : information of cached CoAP messages
  340. * @index : attribute type index for nla_next_start()
  341. *
  342. * Return : 0 on success and errno on failure
  343. */
  344. static int
  345. wlan_cfg80211_coap_fill_buf_info(struct sk_buff *reply_skb,
  346. struct coap_buf_node *info, int index)
  347. {
  348. struct nlattr *attr;
  349. attr = nla_nest_start(reply_skb, index);
  350. if (!attr) {
  351. coap_err("nla_nest_start failed");
  352. return -EINVAL;
  353. }
  354. if (hdd_wlan_nla_put_u64(reply_skb, COAP_ATTR(CACHE_INFO_TS),
  355. info->tsf) ||
  356. nla_put_u32(reply_skb, COAP_ATTR(CACHE_INFO_SRC_IPV4),
  357. info->src_ip) ||
  358. nla_put(reply_skb, COAP_ATTR(CACHE_INFO_MSG),
  359. info->len, info->payload)) {
  360. coap_err("nla_put failed");
  361. return -EINVAL;
  362. }
  363. nla_nest_end(reply_skb, attr);
  364. return 0;
  365. }
  366. /**
  367. * wlan_cfg80211_coap_offload_cache_deliver() - deliver cached CoAP messages
  368. * @wiphy: pointer to wireless wiphy structure.
  369. * @cache_list: list of cached CoAP messages
  370. *
  371. * Return: 0 on success; error number otherwise
  372. */
  373. static int
  374. wlan_cfg80211_coap_offload_cache_deliver(struct wiphy *wiphy,
  375. qdf_list_t *cache_list)
  376. {
  377. struct sk_buff *skb;
  378. uint32_t skb_len = NLMSG_HDRLEN;
  379. struct coap_buf_node *cur, *next;
  380. struct nlattr *attr;
  381. int i = 0, ret;
  382. /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES */
  383. skb_len += nla_total_size(0);
  384. qdf_list_for_each_del(cache_list, cur, next, node) {
  385. if (!cur->len || !cur->payload)
  386. continue;
  387. /* nest attribute */
  388. skb_len += nla_total_size(0);
  389. /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_TS */
  390. skb_len += nla_total_size(sizeof(uint64_t));
  391. /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4 */
  392. skb_len += nla_total_size(sizeof(uint32_t));
  393. /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MSG */
  394. skb_len += nla_total_size(cur->len);
  395. }
  396. skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
  397. attr = nla_nest_start(skb, COAP_ATTR(CACHES));
  398. if (!attr) {
  399. hdd_err("nla_nest_start failed");
  400. wlan_cfg80211_vendor_free_skb(skb);
  401. return -EINVAL;
  402. }
  403. qdf_list_for_each_del(cache_list, cur, next, node) {
  404. if (!cur->len || !cur->payload)
  405. continue;
  406. qdf_list_remove_node(cache_list, &cur->node);
  407. ret = wlan_cfg80211_coap_fill_buf_info(skb, cur, i++);
  408. if (ret) {
  409. wlan_cfg80211_vendor_free_skb(skb);
  410. return -EINVAL;
  411. }
  412. qdf_mem_free(cur->payload);
  413. qdf_mem_free(cur);
  414. }
  415. nla_nest_end(skb, attr);
  416. return wlan_cfg80211_vendor_cmd_reply(skb);
  417. }
  418. /**
  419. * wlan_cfg80211_coap_offload_cache_get() - get cached CoAP messages
  420. * @wiphy: pointer to wireless wiphy structure.
  421. * @vdev: pointer to vdev object
  422. * @req_id: request id
  423. *
  424. * Return: 0 on success; error number otherwise
  425. */
  426. static int
  427. wlan_cfg80211_coap_offload_cache_get(struct wiphy *wiphy,
  428. struct wlan_objmgr_vdev *vdev,
  429. uint32_t req_id)
  430. {
  431. void *cookie;
  432. QDF_STATUS status;
  433. struct osif_request *request;
  434. struct coap_buf_info *buf_info;
  435. int ret;
  436. static const struct osif_request_params params = {
  437. .priv_size = sizeof(*buf_info),
  438. .timeout_ms = COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS,
  439. .dealloc = wlan_cfg80211_dealloc_coap_buf_info,
  440. };
  441. request = osif_request_alloc(&params);
  442. if (!request) {
  443. coap_err("Request allocation failure");
  444. status = QDF_STATUS_E_NOMEM;
  445. goto out;
  446. }
  447. buf_info = osif_request_priv(request);
  448. qdf_list_create(&buf_info->info_list, 0);
  449. buf_info->req_id = req_id;
  450. buf_info->vdev_id = wlan_vdev_get_id(vdev);
  451. cookie = osif_request_cookie(request);
  452. status = ucfg_coap_offload_cache_get(vdev, req_id,
  453. wlan_cfg80211_coap_cache_get_cbk,
  454. cookie);
  455. if (QDF_IS_STATUS_ERROR(status)) {
  456. coap_err("Unable to get cache");
  457. goto out;
  458. }
  459. ret = osif_request_wait_for_response(request);
  460. if (ret) {
  461. coap_err("Target response timed out");
  462. status = qdf_status_from_os_return(ret);
  463. goto out;
  464. }
  465. ret = wlan_cfg80211_coap_offload_cache_deliver(wiphy,
  466. &buf_info->info_list);
  467. if (ret) {
  468. coap_err("Failed to deliver buf info");
  469. status = qdf_status_from_os_return(ret);
  470. goto out;
  471. }
  472. out:
  473. if (request)
  474. osif_request_put(request);
  475. return qdf_status_to_os_return(status);
  476. }
  477. /**
  478. * wlan_cfg80211_coap_offload_reply_disable() - disable CoAP offload reply
  479. * @wiphy: pointer to wireless wiphy structure.
  480. * @vdev: pointer to vdev object
  481. * @req_id: request id
  482. *
  483. * Return: 0 on success; error number otherwise
  484. */
  485. static int
  486. wlan_cfg80211_coap_offload_reply_disable(struct wiphy *wiphy,
  487. struct wlan_objmgr_vdev *vdev,
  488. uint32_t req_id)
  489. {
  490. void *cookie;
  491. QDF_STATUS status;
  492. struct osif_request *request;
  493. struct coap_buf_info *buf_info;
  494. int ret;
  495. static const struct osif_request_params params = {
  496. .priv_size = sizeof(*buf_info),
  497. .timeout_ms = COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS,
  498. .dealloc = wlan_cfg80211_dealloc_coap_buf_info,
  499. };
  500. request = osif_request_alloc(&params);
  501. if (!request) {
  502. coap_err("Request allocation failure");
  503. status = QDF_STATUS_E_NOMEM;
  504. goto out;
  505. }
  506. buf_info = osif_request_priv(request);
  507. qdf_list_create(&buf_info->info_list, 0);
  508. buf_info->req_id = req_id;
  509. buf_info->vdev_id = wlan_vdev_get_id(vdev);
  510. cookie = osif_request_cookie(request);
  511. status = ucfg_coap_offload_reply_disable(vdev, req_id,
  512. wlan_cfg80211_coap_cache_get_cbk, cookie);
  513. if (QDF_IS_STATUS_ERROR(status)) {
  514. coap_err("Failed to disable offload reply");
  515. goto out;
  516. }
  517. ret = osif_request_wait_for_response(request);
  518. if (ret) {
  519. coap_err("Target response timed out");
  520. status = qdf_status_from_os_return(ret);
  521. goto out;
  522. }
  523. ret = wlan_cfg80211_coap_offload_cache_deliver(wiphy,
  524. &buf_info->info_list);
  525. if (ret) {
  526. coap_err("Failed to deliver buf info");
  527. status = qdf_status_from_os_return(ret);
  528. goto out;
  529. }
  530. out:
  531. if (request)
  532. osif_request_put(request);
  533. return qdf_status_to_os_return(status);
  534. }
  535. int
  536. wlan_cfg80211_coap_offload(struct wiphy *wiphy, struct wlan_objmgr_vdev *vdev,
  537. const void *data, int data_len)
  538. {
  539. struct nlattr *tb[COAP_ATTR(MAX) + 1];
  540. struct nlattr *attr;
  541. uint32_t action, req_id;
  542. int ret;
  543. if (wlan_cfg80211_nla_parse(tb, COAP_ATTR(MAX),
  544. data, data_len, coap_offload_policy)) {
  545. coap_err("Invalid ATTR");
  546. return -EINVAL;
  547. }
  548. if (!tb[COAP_ATTR(ACTION)]) {
  549. coap_err("no attr action");
  550. return -EINVAL;
  551. }
  552. if (!tb[COAP_ATTR(REQ_ID)]) {
  553. coap_err("no attr req id");
  554. return -EINVAL;
  555. }
  556. action = nla_get_u32(tb[COAP_ATTR(ACTION)]);
  557. req_id = nla_get_u32(tb[COAP_ATTR(REQ_ID)]);
  558. switch (action) {
  559. case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE:
  560. attr = tb[COAP_ATTR(REPLY)];
  561. ret = wlan_cfg80211_coap_offload_reply_enable(vdev, req_id,
  562. attr);
  563. break;
  564. case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE:
  565. ret = wlan_cfg80211_coap_offload_reply_disable(wiphy, vdev,
  566. req_id);
  567. break;
  568. case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE:
  569. attr = tb[COAP_ATTR(PERIODIC_TX)];
  570. ret = wlan_cfg80211_coap_offload_periodic_tx_enable(vdev,
  571. req_id,
  572. attr);
  573. break;
  574. case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_DISABLE:
  575. ret = wlan_cfg80211_coap_offload_periodic_tx_disable(vdev,
  576. req_id);
  577. break;
  578. case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET:
  579. ret = wlan_cfg80211_coap_offload_cache_get(wiphy, vdev,
  580. req_id);
  581. break;
  582. default:
  583. ret = -EINVAL;
  584. break;
  585. }
  586. coap_debug("vdev_id %u action %u req id %u ret %d",
  587. wlan_vdev_get_id(vdev), action, req_id, ret);
  588. return ret;
  589. }