123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683 |
- /*
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- /**
- * DOC: defines driver functions interfacing with linux kernel
- */
- #include <wmi_unified_param.h>
- #include <wlan_osif_request_manager.h>
- #include <osif_sync.h>
- #include <wlan_objmgr_psoc_obj.h>
- #include <wlan_hdd_main.h>
- #include <wlan_coap_main.h>
- #include <wlan_coap_ucfg_api.h>
- #include <wlan_cfg80211_coap.h>
- #define COAP_MATCH_DATA_BYTES_MAX 16
- #define COAP_MSG_BYTES_MAX 1152
- #define COAP_OFFLOAD_REPLY_CACHE_EXPTIME_MS 40000
- #define COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS 2000
- #define COAP_ATTR(_name) QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ ## _name
- static const struct nla_policy
- coap_offload_filter_policy[COAP_ATTR(FILTER_MAX) + 1] = {
- [COAP_ATTR(FILTER_DEST_IPV4)] = {.type = NLA_U32},
- [COAP_ATTR(FILTER_DEST_IPV4_IS_BC)] = {.type = NLA_FLAG},
- [COAP_ATTR(FILTER_DEST_PORT)] = {.type = NLA_U16},
- [COAP_ATTR(FILTER_MATCH_OFFSET)] = {.type = NLA_U32},
- [COAP_ATTR(FILTER_MATCH_DATA)] = {
- .type = NLA_BINARY, .len = COAP_MATCH_DATA_BYTES_MAX},
- };
- static const struct nla_policy
- coap_offload_tx_ipv4_policy[COAP_ATTR(TX_IPV4_MAX) + 1] = {
- [COAP_ATTR(TX_IPV4_SRC_ADDR)] = {.type = NLA_U32},
- [COAP_ATTR(TX_IPV4_SRC_PORT)] = {.type = NLA_U16},
- [COAP_ATTR(TX_IPV4_DEST_ADDR)] = {.type = NLA_U32},
- [COAP_ATTR(TX_IPV4_DEST_IS_BC)] = {.type = NLA_FLAG},
- [COAP_ATTR(TX_IPV4_DEST_PORT)] = {.type = NLA_U16},
- };
- static const struct nla_policy
- coap_offload_reply_policy[COAP_ATTR(REPLY_MAX) + 1] = {
- [COAP_ATTR(REPLY_SRC_IPV4)] = {.type = NLA_U32},
- [COAP_ATTR(REPLY_FILTER)] =
- VENDOR_NLA_POLICY_NESTED(coap_offload_filter_policy),
- [COAP_ATTR(REPLY_MSG)] = {
- .type = NLA_BINARY, .len = COAP_MSG_BYTES_MAX},
- [COAP_ATTR(REPLY_CACHE_EXPTIME)] = {.type = NLA_U32},
- };
- static const struct nla_policy
- coap_offload_periodic_tx_policy[COAP_ATTR(PERIODIC_TX_MAX) + 1] = {
- [COAP_ATTR(PERIODIC_TX_IPV4)] =
- VENDOR_NLA_POLICY_NESTED(coap_offload_tx_ipv4_policy),
- [COAP_ATTR(PERIODIC_TX_PERIOD)] = {.type = NLA_U32},
- [COAP_ATTR(PERIODIC_TX_MSG)] = {
- .type = NLA_BINARY, .len = COAP_MSG_BYTES_MAX},
- };
- const struct nla_policy
- coap_offload_policy[COAP_ATTR(MAX) + 1] = {
- [COAP_ATTR(ACTION)] = {.type = NLA_U32 },
- [COAP_ATTR(REQ_ID)] = {.type = NLA_U32 },
- [COAP_ATTR(REPLY)] =
- VENDOR_NLA_POLICY_NESTED(coap_offload_reply_policy),
- [COAP_ATTR(PERIODIC_TX)] =
- VENDOR_NLA_POLICY_NESTED(coap_offload_periodic_tx_policy),
- };
- /**
- * wlan_cfg80211_coap_offload_reply_fill_filter() - fill filter for CoAP
- * offload reply.
- * @attr_filter: pointer to filter attribute
- * @params: pointer to parameters for CoAP offload reply
- *
- * Return: 0 on success; error number otherwise
- */
- static int
- wlan_cfg80211_coap_offload_reply_fill_filter(struct nlattr *attr_filter,
- struct coap_offload_reply_param *params)
- {
- struct nlattr *tb[COAP_ATTR(FILTER_MAX) + 1];
- if (!attr_filter) {
- coap_err("No ATTR filter");
- return -EINVAL;
- }
- if (!nla_data(attr_filter)) {
- coap_err("Invalid filter");
- return -EINVAL;
- }
- if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(FILTER_MAX),
- attr_filter,
- coap_offload_filter_policy)) {
- coap_err("Invalid ATTR");
- return -EINVAL;
- }
- if (!tb[COAP_ATTR(FILTER_DEST_IPV4)]) {
- coap_err("no ATTR dest IPv4");
- return -EINVAL;
- }
- params->dest_ip_v4 = nla_get_u32(tb[COAP_ATTR(FILTER_DEST_IPV4)]);
- params->dest_ip_v4_is_bc =
- nla_get_flag(tb[COAP_ATTR(FILTER_DEST_IPV4_IS_BC)]);
- if (!tb[COAP_ATTR(FILTER_DEST_PORT)]) {
- coap_err("no ATTR dest IPv4 port");
- return -EINVAL;
- }
- params->dest_udp_port = nla_get_u16(tb[COAP_ATTR(FILTER_DEST_PORT)]);
- if (!tb[COAP_ATTR(FILTER_MATCH_OFFSET)]) {
- coap_err("no ATTR match offset");
- return -EINVAL;
- }
- params->verify_offset =
- nla_get_u32(tb[COAP_ATTR(FILTER_MATCH_OFFSET)]);
- if (!tb[COAP_ATTR(FILTER_MATCH_DATA)]) {
- coap_err("no ATTR match data");
- return -EINVAL;
- }
- params->verify_len = nla_len(tb[COAP_ATTR(FILTER_MATCH_DATA)]);
- if (!params->verify_len) {
- coap_err("invalid match data len");
- return -EINVAL;
- }
- params->verify = nla_data(tb[COAP_ATTR(FILTER_MATCH_DATA)]);
- return 0;
- }
- /**
- * wlan_cfg80211_coap_offload_reply_enable() - enable CoAP offload reply
- * @vdev: pointer to vdev object
- * @req_id: request id
- * @attr_reply: pointer to CoAP offload reply attribute
- *
- * Return: 0 on success; error number otherwise
- */
- static int
- wlan_cfg80211_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev,
- uint32_t req_id,
- struct nlattr *attr_reply)
- {
- struct nlattr *tb[COAP_ATTR(REPLY_MAX) + 1];
- struct coap_offload_reply_param params = {0};
- struct nlattr *attr;
- QDF_STATUS status;
- int ret;
- if (!attr_reply) {
- coap_err("No ATTR reply");
- return -EINVAL;
- }
- if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(REPLY_MAX),
- attr_reply,
- coap_offload_reply_policy)) {
- coap_err("Invalid ATTR");
- return -EINVAL;
- }
- attr = tb[COAP_ATTR(REPLY_SRC_IPV4)];
- if (!attr) {
- coap_err("No ATTR IPv4");
- return -EINVAL;
- }
- params.src_ip_v4 = nla_get_u32(attr);
- attr = tb[COAP_ATTR(REPLY_FILTER)];
- ret = wlan_cfg80211_coap_offload_reply_fill_filter(attr, ¶ms);
- if (ret)
- return ret;
- attr = tb[COAP_ATTR(REPLY_MSG)];
- if (!attr) {
- coap_err("No ATTR msg");
- return -EINVAL;
- }
- params.coapmsg_len = nla_len(attr);
- params.coapmsg = nla_data(attr);
- attr = tb[COAP_ATTR(REPLY_CACHE_EXPTIME)];
- if (!attr)
- params.cache_timeout = COAP_OFFLOAD_REPLY_CACHE_EXPTIME_MS;
- else
- params.cache_timeout = nla_get_u32(attr);
- status = ucfg_coap_offload_reply_enable(vdev, ¶ms);
- ret = qdf_status_to_os_return(status);
- return ret;
- }
- /**
- * wlan_cfg80211_coap_offload_fill_tx_ipv4() - fill IPv4 source/destination
- * address/port for offload transmitting.
- * @attr_ipv4: pointer to TX IPv4 attribute
- * @params: pointer to parameters for CoAP offload reply
- *
- * Return: 0 on success; error number otherwise
- */
- static int
- wlan_cfg80211_coap_offload_fill_tx_ipv4(struct nlattr *attr_ipv4,
- struct coap_offload_periodic_tx_param *params)
- {
- struct nlattr *tb[COAP_ATTR(TX_IPV4_MAX) + 1];
- if (!attr_ipv4) {
- coap_err("No ATTR TX IPv4");
- return -EINVAL;
- }
- if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(TX_IPV4_MAX),
- attr_ipv4,
- coap_offload_tx_ipv4_policy)) {
- coap_err("Invalid ATTR");
- return -EINVAL;
- }
- if (!tb[COAP_ATTR(TX_IPV4_SRC_ADDR)]) {
- coap_err("no ATTR src addr");
- return -EINVAL;
- }
- params->src_ip_v4 = nla_get_u32(tb[COAP_ATTR(TX_IPV4_SRC_ADDR)]);
- if (tb[COAP_ATTR(TX_IPV4_SRC_PORT)])
- params->src_udp_port =
- nla_get_u32(tb[COAP_ATTR(TX_IPV4_SRC_PORT)]);
- if (!tb[COAP_ATTR(TX_IPV4_DEST_ADDR)]) {
- coap_err("no ATTR IPv4 dest addr");
- return -EINVAL;
- }
- params->dest_ip_v4 = nla_get_u32(tb[COAP_ATTR(TX_IPV4_DEST_ADDR)]);
- params->dest_ip_v4_is_bc =
- nla_get_flag(tb[COAP_ATTR(TX_IPV4_DEST_IS_BC)]);
- if (!tb[COAP_ATTR(TX_IPV4_DEST_PORT)]) {
- coap_err("no ATTR dest IPv4 port");
- return -EINVAL;
- }
- params->dest_udp_port =
- nla_get_u32(tb[COAP_ATTR(TX_IPV4_DEST_PORT)]);
- return 0;
- }
- /**
- * wlan_cfg80211_coap_offload_periodic_tx_enable() - enable CoAP offload
- * periodic transmitting
- * @vdev: pointer to vdev object
- * @req_id: request id
- * @attr_reply: pointer to CoAP offload periodic TX attribute
- *
- * Return: 0 on success; error number otherwise
- */
- static int
- wlan_cfg80211_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev,
- uint32_t req_id,
- struct nlattr *attr_periodic_tx)
- {
- struct nlattr *tb[COAP_ATTR(PERIODIC_TX_MAX) + 1];
- struct coap_offload_periodic_tx_param param = {0};
- struct nlattr *attr_ipv4;
- QDF_STATUS status;
- int ret;
- if (!attr_periodic_tx) {
- coap_err("No ATTR periodic tx");
- return -EINVAL;
- }
- if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(PERIODIC_TX_MAX),
- attr_periodic_tx,
- coap_offload_periodic_tx_policy)) {
- coap_err("Invalid ATTR");
- return -EINVAL;
- }
- if (!tb[COAP_ATTR(PERIODIC_TX_PERIOD)]) {
- coap_err("no ATTR period");
- return -EINVAL;
- }
- param.timeout = nla_get_u32(tb[COAP_ATTR(PERIODIC_TX_PERIOD)]);
- attr_ipv4 = tb[COAP_ATTR(PERIODIC_TX_IPV4)];
- ret = wlan_cfg80211_coap_offload_fill_tx_ipv4(attr_ipv4, ¶m);
- if (ret)
- return ret;
- param.vdev_id = wlan_vdev_get_id(vdev);
- param.pattern_id = req_id;
- if (!tb[COAP_ATTR(PERIODIC_TX_MSG)]) {
- coap_err("no ATTR msg");
- return -EINVAL;
- }
- param.coapmsg_len = nla_len(tb[COAP_ATTR(PERIODIC_TX_MSG)]);
- param.coapmsg = nla_data(tb[COAP_ATTR(PERIODIC_TX_MSG)]);
- status = ucfg_coap_offload_periodic_tx_enable(vdev, ¶m);
- return qdf_status_to_os_return(status);
- }
- /**
- * wlan_cfg80211_coap_offload_periodic_tx_enable() - disable CoAP offload
- * periodic transmitting
- * @vdev: pointer to vdev object
- * @req_id: request id
- *
- * Return: 0 on success; error number otherwise
- */
- static int
- wlan_cfg80211_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev,
- uint32_t req_id)
- {
- QDF_STATUS status;
- status = ucfg_coap_offload_periodic_tx_disable(vdev, req_id);
- return qdf_status_to_os_return(status);
- }
- /**
- * wlan_cfg80211_dealloc_coap_buf_info() - Callback to free priv
- * allocations for CoAP buffer info
- * @priv: Pointer to priv data statucture
- *
- * Return: None
- */
- static void wlan_cfg80211_dealloc_coap_buf_info(void *priv)
- {
- struct coap_buf_info *info = priv;
- struct coap_buf_node *cur, *next;
- if (!info)
- return;
- qdf_list_for_each_del(&info->info_list, cur, next, node) {
- qdf_list_remove_node(&info->info_list, &cur->node);
- qdf_mem_free(cur->payload);
- qdf_mem_free(cur);
- }
- qdf_list_destroy(&info->info_list);
- }
- static void
- wlan_cfg80211_coap_cache_get_cbk(void *context, struct coap_buf_info *info)
- {
- struct osif_request *request;
- struct coap_buf_info *priv_info;
- if (!context || !info)
- return;
- request = osif_request_get(context);
- if (!request)
- return;
- priv_info = osif_request_priv(request);
- if (info->req_id != priv_info->req_id)
- return;
- qdf_list_join(&priv_info->info_list, &info->info_list);
- if (info->more_info)
- return;
- osif_request_complete(request);
- osif_request_put(request);
- }
- /**
- * wlan_cfg80211_coap_fill_buf_info() - Fill cache get response buffer
- * @reply_skb : pointer to reply_skb
- * @info : information of cached CoAP messages
- * @index : attribute type index for nla_next_start()
- *
- * Return : 0 on success and errno on failure
- */
- static int
- wlan_cfg80211_coap_fill_buf_info(struct sk_buff *reply_skb,
- struct coap_buf_node *info, int index)
- {
- struct nlattr *attr;
- attr = nla_nest_start(reply_skb, index);
- if (!attr) {
- coap_err("nla_nest_start failed");
- return -EINVAL;
- }
- if (hdd_wlan_nla_put_u64(reply_skb, COAP_ATTR(CACHE_INFO_TS),
- info->tsf) ||
- nla_put_u32(reply_skb, COAP_ATTR(CACHE_INFO_SRC_IPV4),
- info->src_ip) ||
- nla_put(reply_skb, COAP_ATTR(CACHE_INFO_MSG),
- info->len, info->payload)) {
- coap_err("nla_put failed");
- return -EINVAL;
- }
- nla_nest_end(reply_skb, attr);
- return 0;
- }
- /**
- * wlan_cfg80211_coap_offload_cache_deliver() - deliver cached CoAP messages
- * @wiphy: pointer to wireless wiphy structure.
- * @cache_list: list of cached CoAP messages
- *
- * Return: 0 on success; error number otherwise
- */
- static int
- wlan_cfg80211_coap_offload_cache_deliver(struct wiphy *wiphy,
- qdf_list_t *cache_list)
- {
- struct sk_buff *skb;
- uint32_t skb_len = NLMSG_HDRLEN;
- struct coap_buf_node *cur, *next;
- struct nlattr *attr;
- int i = 0, ret;
- /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES */
- skb_len += nla_total_size(0);
- qdf_list_for_each_del(cache_list, cur, next, node) {
- if (!cur->len || !cur->payload)
- continue;
- /* nest attribute */
- skb_len += nla_total_size(0);
- /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_TS */
- skb_len += nla_total_size(sizeof(uint64_t));
- /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4 */
- skb_len += nla_total_size(sizeof(uint32_t));
- /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MSG */
- skb_len += nla_total_size(cur->len);
- }
- skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
- attr = nla_nest_start(skb, COAP_ATTR(CACHES));
- if (!attr) {
- hdd_err("nla_nest_start failed");
- wlan_cfg80211_vendor_free_skb(skb);
- return -EINVAL;
- }
- qdf_list_for_each_del(cache_list, cur, next, node) {
- if (!cur->len || !cur->payload)
- continue;
- qdf_list_remove_node(cache_list, &cur->node);
- ret = wlan_cfg80211_coap_fill_buf_info(skb, cur, i++);
- if (ret) {
- wlan_cfg80211_vendor_free_skb(skb);
- return -EINVAL;
- }
- qdf_mem_free(cur->payload);
- qdf_mem_free(cur);
- }
- nla_nest_end(skb, attr);
- return wlan_cfg80211_vendor_cmd_reply(skb);
- }
- /**
- * wlan_cfg80211_coap_offload_cache_get() - get cached CoAP messages
- * @wiphy: pointer to wireless wiphy structure.
- * @vdev: pointer to vdev object
- * @req_id: request id
- *
- * Return: 0 on success; error number otherwise
- */
- static int
- wlan_cfg80211_coap_offload_cache_get(struct wiphy *wiphy,
- struct wlan_objmgr_vdev *vdev,
- uint32_t req_id)
- {
- void *cookie;
- QDF_STATUS status;
- struct osif_request *request;
- struct coap_buf_info *buf_info;
- int ret;
- static const struct osif_request_params params = {
- .priv_size = sizeof(*buf_info),
- .timeout_ms = COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS,
- .dealloc = wlan_cfg80211_dealloc_coap_buf_info,
- };
- request = osif_request_alloc(¶ms);
- if (!request) {
- coap_err("Request allocation failure");
- status = QDF_STATUS_E_NOMEM;
- goto out;
- }
- buf_info = osif_request_priv(request);
- qdf_list_create(&buf_info->info_list, 0);
- buf_info->req_id = req_id;
- buf_info->vdev_id = wlan_vdev_get_id(vdev);
- cookie = osif_request_cookie(request);
- status = ucfg_coap_offload_cache_get(vdev, req_id,
- wlan_cfg80211_coap_cache_get_cbk,
- cookie);
- if (QDF_IS_STATUS_ERROR(status)) {
- coap_err("Unable to get cache");
- goto out;
- }
- ret = osif_request_wait_for_response(request);
- if (ret) {
- coap_err("Target response timed out");
- status = qdf_status_from_os_return(ret);
- goto out;
- }
- ret = wlan_cfg80211_coap_offload_cache_deliver(wiphy,
- &buf_info->info_list);
- if (ret) {
- coap_err("Failed to deliver buf info");
- status = qdf_status_from_os_return(ret);
- goto out;
- }
- out:
- if (request)
- osif_request_put(request);
- return qdf_status_to_os_return(status);
- }
- /**
- * wlan_cfg80211_coap_offload_reply_disable() - disable CoAP offload reply
- * @wiphy: pointer to wireless wiphy structure.
- * @vdev: pointer to vdev object
- * @req_id: request id
- *
- * Return: 0 on success; error number otherwise
- */
- static int
- wlan_cfg80211_coap_offload_reply_disable(struct wiphy *wiphy,
- struct wlan_objmgr_vdev *vdev,
- uint32_t req_id)
- {
- void *cookie;
- QDF_STATUS status;
- struct osif_request *request;
- struct coap_buf_info *buf_info;
- int ret;
- static const struct osif_request_params params = {
- .priv_size = sizeof(*buf_info),
- .timeout_ms = COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS,
- .dealloc = wlan_cfg80211_dealloc_coap_buf_info,
- };
- request = osif_request_alloc(¶ms);
- if (!request) {
- coap_err("Request allocation failure");
- status = QDF_STATUS_E_NOMEM;
- goto out;
- }
- buf_info = osif_request_priv(request);
- qdf_list_create(&buf_info->info_list, 0);
- buf_info->req_id = req_id;
- buf_info->vdev_id = wlan_vdev_get_id(vdev);
- cookie = osif_request_cookie(request);
- status = ucfg_coap_offload_reply_disable(vdev, req_id,
- wlan_cfg80211_coap_cache_get_cbk, cookie);
- if (QDF_IS_STATUS_ERROR(status)) {
- coap_err("Failed to disable offload reply");
- goto out;
- }
- ret = osif_request_wait_for_response(request);
- if (ret) {
- coap_err("Target response timed out");
- status = qdf_status_from_os_return(ret);
- goto out;
- }
- ret = wlan_cfg80211_coap_offload_cache_deliver(wiphy,
- &buf_info->info_list);
- if (ret) {
- coap_err("Failed to deliver buf info");
- status = qdf_status_from_os_return(ret);
- goto out;
- }
- out:
- if (request)
- osif_request_put(request);
- return qdf_status_to_os_return(status);
- }
- int
- wlan_cfg80211_coap_offload(struct wiphy *wiphy, struct wlan_objmgr_vdev *vdev,
- const void *data, int data_len)
- {
- struct nlattr *tb[COAP_ATTR(MAX) + 1];
- struct nlattr *attr;
- uint32_t action, req_id;
- int ret;
- if (wlan_cfg80211_nla_parse(tb, COAP_ATTR(MAX),
- data, data_len, coap_offload_policy)) {
- coap_err("Invalid ATTR");
- return -EINVAL;
- }
- if (!tb[COAP_ATTR(ACTION)]) {
- coap_err("no attr action");
- return -EINVAL;
- }
- if (!tb[COAP_ATTR(REQ_ID)]) {
- coap_err("no attr req id");
- return -EINVAL;
- }
- action = nla_get_u32(tb[COAP_ATTR(ACTION)]);
- req_id = nla_get_u32(tb[COAP_ATTR(REQ_ID)]);
- switch (action) {
- case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE:
- attr = tb[COAP_ATTR(REPLY)];
- ret = wlan_cfg80211_coap_offload_reply_enable(vdev, req_id,
- attr);
- break;
- case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE:
- ret = wlan_cfg80211_coap_offload_reply_disable(wiphy, vdev,
- req_id);
- break;
- case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE:
- attr = tb[COAP_ATTR(PERIODIC_TX)];
- ret = wlan_cfg80211_coap_offload_periodic_tx_enable(vdev,
- req_id,
- attr);
- break;
- case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_DISABLE:
- ret = wlan_cfg80211_coap_offload_periodic_tx_disable(vdev,
- req_id);
- break;
- case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET:
- ret = wlan_cfg80211_coap_offload_cache_get(wiphy, vdev,
- req_id);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- coap_debug("vdev_id %u action %u req id %u ret %d",
- wlan_vdev_get_id(vdev), action, req_id, ret);
- return ret;
- }
|