Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 1 | /* |
Nachiket Kukade | 338547b | 2019-01-03 18:50:46 +0530 | [diff] [blame^] | 2 | * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for |
| 5 | * any purpose with or without fee is hereby granted, provided that the |
| 6 | * above copyright notice and this permission notice appear in all |
| 7 | * copies. |
| 8 | * |
| 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| 10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| 11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| 12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| 13 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| 14 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| 15 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 16 | * PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ |
| 18 | |
| 19 | /** |
| 20 | * DOC: wlan_hdd_apf.c |
| 21 | * |
| 22 | * Android Packet Filter support and implementation |
| 23 | */ |
| 24 | |
| 25 | #include "wlan_hdd_apf.h" |
| 26 | #include "qca_vendor.h" |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 27 | #include "wlan_osif_request_manager.h" |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 28 | |
| 29 | /* |
| 30 | * define short names for the global vendor params |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 31 | * used by __wlan_hdd_cfg80211_apf_offload() |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 32 | */ |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 33 | #define APF_INVALID \ |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 34 | QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 35 | #define APF_SUBCMD \ |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 36 | QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 37 | #define APF_VERSION \ |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 38 | QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 39 | #define APF_FILTER_ID \ |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 40 | QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 41 | #define APF_PACKET_SIZE \ |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 42 | QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 43 | #define APF_CURRENT_OFFSET \ |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 44 | QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 45 | #define APF_PROGRAM \ |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 46 | QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 47 | #define APF_PROG_LEN \ |
| 48 | QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 49 | #define APF_MAX \ |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 50 | QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX |
| 51 | |
| 52 | static const struct nla_policy |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 53 | wlan_hdd_apf_offload_policy[APF_MAX + 1] = { |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 54 | [APF_SUBCMD] = {.type = NLA_U32}, |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 55 | [APF_VERSION] = {.type = NLA_U32}, |
| 56 | [APF_FILTER_ID] = {.type = NLA_U32}, |
| 57 | [APF_PACKET_SIZE] = {.type = NLA_U32}, |
| 58 | [APF_CURRENT_OFFSET] = {.type = NLA_U32}, |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 59 | [APF_PROGRAM] = {.type = NLA_BINARY, |
| 60 | .len = MAX_APF_MEMORY_LEN}, |
| 61 | [APF_PROG_LEN] = {.type = NLA_U32}, |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 62 | }; |
| 63 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 64 | void hdd_apf_context_init(struct hdd_adapter *adapter) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 65 | { |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 66 | qdf_event_create(&adapter->apf_context.qdf_apf_event); |
| 67 | qdf_spinlock_create(&adapter->apf_context.lock); |
| 68 | adapter->apf_context.apf_enabled = true; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 69 | } |
| 70 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 71 | void hdd_apf_context_destroy(struct hdd_adapter *adapter) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 72 | { |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 73 | qdf_event_destroy(&adapter->apf_context.qdf_apf_event); |
| 74 | qdf_spinlock_destroy(&adapter->apf_context.lock); |
| 75 | qdf_mem_zero(&adapter->apf_context, |
| 76 | sizeof(struct hdd_apf_context)); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 77 | } |
| 78 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 79 | struct apf_offload_priv { |
| 80 | struct sir_apf_get_offload apf_get_offload; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 81 | }; |
| 82 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 83 | void hdd_get_apf_capabilities_cb(void *context, |
| 84 | struct sir_apf_get_offload *data) |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 85 | { |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 86 | struct osif_request *request; |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 87 | struct apf_offload_priv *priv; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 88 | |
| 89 | hdd_enter(); |
| 90 | |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 91 | request = osif_request_get(context); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 92 | if (!request) { |
| 93 | hdd_err("Obsolete request"); |
| 94 | return; |
| 95 | } |
| 96 | |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 97 | priv = osif_request_priv(request); |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 98 | priv->apf_get_offload = *data; |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 99 | osif_request_complete(request); |
| 100 | osif_request_put(request); |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 101 | |
| 102 | hdd_exit(); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 103 | } |
| 104 | |
| 105 | /** |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 106 | * hdd_post_get_apf_capabilities_rsp() - Callback function to APF Offload |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 107 | * @hdd_context: hdd_context |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 108 | * @apf_get_offload: struct for get offload |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 109 | * |
| 110 | * Return: 0 on success, error number otherwise. |
| 111 | */ |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 112 | static int |
| 113 | hdd_post_get_apf_capabilities_rsp(struct hdd_context *hdd_ctx, |
| 114 | struct sir_apf_get_offload *apf_get_offload) |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 115 | { |
| 116 | struct sk_buff *skb; |
| 117 | uint32_t nl_buf_len; |
| 118 | |
| 119 | hdd_enter(); |
| 120 | |
| 121 | nl_buf_len = NLMSG_HDRLEN; |
| 122 | nl_buf_len += |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 123 | (sizeof(apf_get_offload->max_bytes_for_apf_inst) + NLA_HDRLEN) + |
| 124 | (sizeof(apf_get_offload->apf_version) + NLA_HDRLEN); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 125 | |
| 126 | skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); |
| 127 | if (!skb) { |
| 128 | hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); |
| 129 | return -ENOMEM; |
| 130 | } |
| 131 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 132 | hdd_ctx->apf_version = apf_get_offload->apf_version; |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 133 | hdd_debug("APF Version: %u APF max bytes: %u", |
| 134 | apf_get_offload->apf_version, |
| 135 | apf_get_offload->max_bytes_for_apf_inst); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 136 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 137 | if (nla_put_u32(skb, APF_PACKET_SIZE, |
| 138 | apf_get_offload->max_bytes_for_apf_inst) || |
| 139 | nla_put_u32(skb, APF_VERSION, apf_get_offload->apf_version)) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 140 | hdd_err("nla put failure"); |
| 141 | goto nla_put_failure; |
| 142 | } |
| 143 | |
| 144 | cfg80211_vendor_cmd_reply(skb); |
| 145 | hdd_exit(); |
| 146 | return 0; |
| 147 | |
| 148 | nla_put_failure: |
| 149 | kfree_skb(skb); |
| 150 | return -EINVAL; |
| 151 | } |
| 152 | |
| 153 | /** |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 154 | * hdd_get_apf_capabilities - Get APF offload Capabilities |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 155 | * @hdd_ctx: Hdd context |
| 156 | * |
| 157 | * Return: 0 on success, errno on failure |
| 158 | */ |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 159 | static int hdd_get_apf_capabilities(struct hdd_context *hdd_ctx) |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 160 | { |
| 161 | QDF_STATUS status; |
| 162 | int ret; |
| 163 | void *cookie; |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 164 | struct osif_request *request; |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 165 | struct apf_offload_priv *priv; |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 166 | static const struct osif_request_params params = { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 167 | .priv_size = sizeof(*priv), |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 168 | .timeout_ms = WLAN_WAIT_TIME_APF, |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 169 | }; |
| 170 | |
| 171 | hdd_enter(); |
| 172 | |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 173 | request = osif_request_alloc(¶ms); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 174 | if (!request) { |
| 175 | hdd_err("Unable to allocate request"); |
| 176 | return -EINVAL; |
| 177 | } |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 178 | cookie = osif_request_cookie(request); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 179 | |
Jeff Johnson | c616223 | 2018-06-20 13:33:07 -0700 | [diff] [blame] | 180 | status = sme_get_apf_capabilities(hdd_ctx->mac_handle, |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 181 | hdd_get_apf_capabilities_cb, |
| 182 | cookie); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 183 | if (!QDF_IS_STATUS_SUCCESS(status)) { |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 184 | hdd_err("Unable to retrieve APF caps"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 185 | ret = qdf_status_to_os_return(status); |
| 186 | goto cleanup; |
| 187 | } |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 188 | ret = osif_request_wait_for_response(request); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 189 | if (ret) { |
| 190 | hdd_err("Target response timed out"); |
| 191 | goto cleanup; |
| 192 | } |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 193 | priv = osif_request_priv(request); |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 194 | ret = hdd_post_get_apf_capabilities_rsp(hdd_ctx, |
| 195 | &priv->apf_get_offload); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 196 | if (ret) |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 197 | hdd_err("Failed to post get apf capabilities"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 198 | |
| 199 | cleanup: |
| 200 | /* |
| 201 | * either we never sent a request to SME, we sent a request to |
| 202 | * SME and timed out, or we sent a request to SME, received a |
| 203 | * response from SME, and posted the response to userspace. |
| 204 | * regardless we are done with the request. |
| 205 | */ |
Jeff Johnson | f1a99ea | 2018-06-28 13:27:01 -0700 | [diff] [blame] | 206 | osif_request_put(request); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 207 | hdd_exit(); |
| 208 | |
| 209 | return ret; |
| 210 | } |
| 211 | |
| 212 | /** |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 213 | * hdd_set_reset_apf_offload - Post set/reset apf to SME |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 214 | * @hdd_ctx: Hdd context |
| 215 | * @tb: Length of @data |
| 216 | * @adapter: pointer to adapter struct |
| 217 | * |
| 218 | * Return: 0 on success; errno on failure |
| 219 | */ |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 220 | static int hdd_set_reset_apf_offload(struct hdd_context *hdd_ctx, |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 221 | struct nlattr **tb, |
| 222 | struct hdd_adapter *adapter) |
| 223 | { |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 224 | struct sir_apf_set_offload apf_set_offload = {0}; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 225 | QDF_STATUS status; |
| 226 | int prog_len; |
| 227 | int ret = 0; |
| 228 | |
| 229 | hdd_enter(); |
| 230 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 231 | if (!hdd_conn_is_connected( |
| 232 | WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { |
| 233 | hdd_err("Not in Connected state!"); |
| 234 | return -ENOTSUPP; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 235 | } |
| 236 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 237 | /* Parse and fetch apf packet size */ |
| 238 | if (!tb[APF_PACKET_SIZE]) { |
| 239 | hdd_err("attr apf packet size failed"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 240 | ret = -EINVAL; |
| 241 | goto fail; |
| 242 | } |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 243 | apf_set_offload.total_length = nla_get_u32(tb[APF_PACKET_SIZE]); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 244 | |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 245 | if (!apf_set_offload.total_length) { |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 246 | hdd_debug("APF reset packet filter received"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 247 | goto post_sme; |
| 248 | } |
| 249 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 250 | /* Parse and fetch apf program */ |
| 251 | if (!tb[APF_PROGRAM]) { |
| 252 | hdd_err("attr apf program failed"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 253 | ret = -EINVAL; |
| 254 | goto fail; |
| 255 | } |
| 256 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 257 | prog_len = nla_len(tb[APF_PROGRAM]); |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 258 | apf_set_offload.program = qdf_mem_malloc(sizeof(uint8_t) * prog_len); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 259 | |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 260 | if (!apf_set_offload.program) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 261 | ret = -ENOMEM; |
| 262 | goto fail; |
| 263 | } |
| 264 | |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 265 | apf_set_offload.current_length = prog_len; |
| 266 | nla_memcpy(apf_set_offload.program, tb[APF_PROGRAM], prog_len); |
| 267 | apf_set_offload.session_id = adapter->session_id; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 268 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 269 | hdd_debug("APF set instructions"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 270 | QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 271 | apf_set_offload.program, prog_len); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 272 | |
| 273 | /* Parse and fetch filter Id */ |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 274 | if (!tb[APF_FILTER_ID]) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 275 | hdd_err("attr filter id failed"); |
| 276 | ret = -EINVAL; |
| 277 | goto fail; |
| 278 | } |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 279 | apf_set_offload.filter_id = nla_get_u32(tb[APF_FILTER_ID]); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 280 | |
| 281 | /* Parse and fetch current offset */ |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 282 | if (!tb[APF_CURRENT_OFFSET]) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 283 | hdd_err("attr current offset failed"); |
| 284 | ret = -EINVAL; |
| 285 | goto fail; |
| 286 | } |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 287 | apf_set_offload.current_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 288 | |
| 289 | post_sme: |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 290 | hdd_debug("Posting APF SET/RESET to SME, session_id: %d APF Version: %d filter ID: %d total_length: %d current_length: %d current offset: %d", |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 291 | apf_set_offload.session_id, apf_set_offload.version, |
| 292 | apf_set_offload.filter_id, apf_set_offload.total_length, |
| 293 | apf_set_offload.current_length, |
| 294 | apf_set_offload.current_offset); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 295 | |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 296 | status = sme_set_apf_instructions(hdd_ctx->mac_handle, |
| 297 | &apf_set_offload); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 298 | if (!QDF_IS_STATUS_SUCCESS(status)) { |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 299 | hdd_err("sme_set_apf_instructions failed(err=%d)", status); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 300 | ret = -EINVAL; |
| 301 | goto fail; |
| 302 | } |
| 303 | hdd_exit(); |
| 304 | |
| 305 | fail: |
Nachiket Kukade | 4f68658 | 2018-11-19 19:18:27 +0530 | [diff] [blame] | 306 | if (apf_set_offload.current_length) |
| 307 | qdf_mem_free(apf_set_offload.program); |
Rajeev Kumar Sirasanagandla | 85f8b02 | 2018-03-12 12:52:59 +0530 | [diff] [blame] | 308 | |
| 309 | if (!ret) |
| 310 | hdd_ctx->apf_enabled_v2 = true; |
| 311 | |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 312 | return ret; |
| 313 | } |
| 314 | |
| 315 | /** |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 316 | * hdd_enable_disable_apf - Enable or Disable the APF interpreter |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 317 | * @adapter: HDD Adapter |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 318 | * @apf_enable: true: Enable APF Int., false: disable APF Int. |
| 319 | * |
| 320 | * Return: 0 on success, errno on failure |
| 321 | */ |
| 322 | static int |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 323 | hdd_enable_disable_apf(struct hdd_adapter *adapter, bool apf_enable) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 324 | { |
| 325 | QDF_STATUS status; |
| 326 | |
| 327 | hdd_enter(); |
| 328 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 329 | status = sme_set_apf_enable_disable(hdd_adapter_get_mac_handle(adapter), |
| 330 | adapter->session_id, apf_enable); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 331 | if (!QDF_IS_STATUS_SUCCESS(status)) { |
| 332 | hdd_err("Unable to post sme apf enable/disable message (status-%d)", |
| 333 | status); |
| 334 | return -EINVAL; |
| 335 | } |
| 336 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 337 | adapter->apf_context.apf_enabled = apf_enable; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 338 | |
| 339 | hdd_exit(); |
| 340 | return 0; |
| 341 | } |
| 342 | |
| 343 | /** |
| 344 | * hdd_apf_write_memory - Write into the apf work memory |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 345 | * @adapter: HDD Adapter |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 346 | * @tb: list of attributes |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 347 | * |
| 348 | * This function writes code/data into the APF work memory and |
| 349 | * provides program length that is passed on to the interpreter. |
| 350 | * |
| 351 | * Return: 0 on success, errno on failure |
| 352 | */ |
| 353 | static int |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 354 | hdd_apf_write_memory(struct hdd_adapter *adapter, struct nlattr **tb) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 355 | { |
| 356 | struct wmi_apf_write_memory_params write_mem_params = {0}; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 357 | struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 358 | QDF_STATUS status; |
| 359 | int ret = 0; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 360 | |
| 361 | hdd_enter(); |
| 362 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 363 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 364 | write_mem_params.vdev_id = adapter->session_id; |
| 365 | if (adapter->apf_context.apf_enabled) { |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 366 | hdd_err("Cannot get/set when APF interpreter is enabled"); |
| 367 | return -EINVAL; |
| 368 | } |
| 369 | |
| 370 | /* Read program length */ |
| 371 | if (!tb[APF_PROG_LEN]) { |
| 372 | hdd_err("attr program length failed"); |
| 373 | return -EINVAL; |
| 374 | } |
| 375 | write_mem_params.program_len = nla_get_u32(tb[APF_PROG_LEN]); |
| 376 | |
| 377 | /* Read APF work memory offset */ |
| 378 | if (!tb[APF_CURRENT_OFFSET]) { |
| 379 | hdd_err("attr apf packet size failed"); |
| 380 | return -EINVAL; |
| 381 | } |
| 382 | write_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); |
| 383 | |
| 384 | /* Parse and fetch apf program */ |
| 385 | if (!tb[APF_PROGRAM]) { |
| 386 | hdd_err("attr apf program failed"); |
| 387 | return -EINVAL; |
| 388 | } |
| 389 | |
| 390 | write_mem_params.length = nla_len(tb[APF_PROGRAM]); |
| 391 | if (!write_mem_params.length) { |
| 392 | hdd_err("Program attr with empty data"); |
| 393 | return -EINVAL; |
| 394 | } |
| 395 | |
| 396 | write_mem_params.buf = qdf_mem_malloc(sizeof(uint8_t) |
| 397 | * write_mem_params.length); |
Min Liu | 74a1a50 | 2018-10-10 19:59:07 +0800 | [diff] [blame] | 398 | if (!write_mem_params.buf) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 399 | return -EINVAL; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 400 | nla_memcpy(write_mem_params.buf, tb[APF_PROGRAM], |
| 401 | write_mem_params.length); |
| 402 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 403 | write_mem_params.apf_version = hdd_ctx->apf_version; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 404 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 405 | status = sme_apf_write_work_memory(hdd_adapter_get_mac_handle(adapter), |
Jeff Johnson | c616223 | 2018-06-20 13:33:07 -0700 | [diff] [blame] | 406 | &write_mem_params); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 407 | if (!QDF_IS_STATUS_SUCCESS(status)) { |
| 408 | hdd_err("Unable to retrieve APF caps"); |
| 409 | ret = -EINVAL; |
| 410 | } |
| 411 | |
Nachiket Kukade | 338547b | 2019-01-03 18:50:46 +0530 | [diff] [blame^] | 412 | hdd_debug("Writing successful into APF work memory from offset 0x%X:", |
| 413 | write_mem_params.addr_offset); |
| 414 | QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, |
| 415 | write_mem_params.buf, write_mem_params.length); |
| 416 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 417 | if (write_mem_params.buf) |
| 418 | qdf_mem_free(write_mem_params.buf); |
| 419 | |
| 420 | hdd_exit(); |
| 421 | return ret; |
| 422 | } |
| 423 | |
| 424 | /** |
| 425 | * hdd_apf_read_memory_callback - HDD Callback for the APF read memory |
| 426 | * operation |
| 427 | * @context: Hdd context |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 428 | * @evt: APF read memory event response parameters |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 429 | * |
| 430 | * Return: 0 on success, errno on failure |
| 431 | */ |
| 432 | static void |
| 433 | hdd_apf_read_memory_callback(void *hdd_context, |
| 434 | struct wmi_apf_read_memory_resp_event_params *evt) |
| 435 | { |
| 436 | struct hdd_context *hdd_ctx = hdd_context; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 437 | struct hdd_adapter *adapter; |
| 438 | struct hdd_apf_context *context; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 439 | uint8_t *buf_ptr; |
| 440 | uint32_t pkt_offset; |
| 441 | |
| 442 | hdd_enter(); |
| 443 | |
| 444 | if (wlan_hdd_validate_context(hdd_ctx) || !evt) { |
| 445 | hdd_err("HDD context is invalid or event buf(%pK) is null", |
| 446 | evt); |
| 447 | return; |
| 448 | } |
| 449 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 450 | adapter = hdd_get_adapter_by_vdev(hdd_ctx, evt->vdev_id); |
Ashish Kumar Dhanotiya | 04cc7c2 | 2018-05-11 14:43:10 +0530 | [diff] [blame] | 451 | if (hdd_validate_adapter(adapter)) |
| 452 | return; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 453 | context = &adapter->apf_context; |
| 454 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 455 | if (context->magic != APF_CONTEXT_MAGIC) { |
| 456 | /* The caller presumably timed out, nothing to do */ |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 457 | hdd_err("Caller timed out or corrupt magic, simply return"); |
| 458 | return; |
| 459 | } |
| 460 | |
| 461 | if (evt->offset < context->offset) { |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 462 | hdd_err("Offset in read event(%d) smaller than offset in request(%d)!", |
| 463 | evt->offset, context->offset); |
| 464 | return; |
| 465 | } |
| 466 | |
| 467 | /* |
| 468 | * offset in the event is relative to the APF work memory. |
| 469 | * Calculate the packet offset, which gives us the relative |
| 470 | * location in the buffer to start copy into. |
| 471 | */ |
| 472 | pkt_offset = evt->offset - context->offset; |
| 473 | |
| 474 | if (context->buf_len < pkt_offset + evt->length) { |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 475 | hdd_err("Read chunk exceeding allocated space"); |
| 476 | return; |
| 477 | } |
| 478 | buf_ptr = context->buf + pkt_offset; |
| 479 | |
| 480 | qdf_mem_copy(buf_ptr, evt->data, evt->length); |
| 481 | |
| 482 | if (!evt->more_data) { |
| 483 | /* Release the caller after last event, clear magic */ |
| 484 | context->magic = 0; |
| 485 | qdf_event_set(&context->qdf_apf_event); |
| 486 | } |
| 487 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 488 | hdd_exit(); |
| 489 | } |
| 490 | |
| 491 | /** |
| 492 | * hdd_apf_read_memory - Read part of the apf work memory |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 493 | * @adapter: HDD Adapter |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 494 | * @tb: list of attributes |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 495 | * |
| 496 | * Return: 0 on success, errno on failure |
| 497 | */ |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 498 | static int hdd_apf_read_memory(struct hdd_adapter *adapter, struct nlattr **tb) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 499 | { |
| 500 | struct wmi_apf_read_memory_params read_mem_params = {0}; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 501 | struct hdd_apf_context *context = &adapter->apf_context; |
| 502 | struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 503 | QDF_STATUS status; |
| 504 | unsigned long nl_buf_len = NLMSG_HDRLEN; |
| 505 | int ret = 0; |
| 506 | struct sk_buff *skb = NULL; |
| 507 | uint8_t *bufptr; |
| 508 | |
| 509 | hdd_enter(); |
| 510 | |
Rajeev Kumar | 75fc36e | 2018-09-04 11:41:10 -0700 | [diff] [blame] | 511 | if (context->apf_enabled) { |
| 512 | hdd_err("Cannot get/set while interpreter is enabled"); |
| 513 | return -EINVAL; |
| 514 | } |
| 515 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 516 | read_mem_params.vdev_id = adapter->session_id; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 517 | |
| 518 | /* Read APF work memory offset */ |
| 519 | if (!tb[APF_CURRENT_OFFSET]) { |
| 520 | hdd_err("attr apf memory offset failed"); |
| 521 | return -EINVAL; |
| 522 | } |
| 523 | read_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); |
| 524 | |
| 525 | /* Read length */ |
| 526 | if (!tb[APF_PACKET_SIZE]) { |
| 527 | hdd_err("attr apf packet size failed"); |
| 528 | return -EINVAL; |
| 529 | } |
| 530 | read_mem_params.length = nla_get_u32(tb[APF_PACKET_SIZE]); |
| 531 | if (!read_mem_params.length) { |
| 532 | hdd_err("apf read length cannot be zero!"); |
| 533 | return -EINVAL; |
| 534 | } |
| 535 | bufptr = qdf_mem_malloc(read_mem_params.length); |
Min Liu | 74a1a50 | 2018-10-10 19:59:07 +0800 | [diff] [blame] | 536 | if (!bufptr) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 537 | return -ENOMEM; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 538 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 539 | qdf_event_reset(&context->qdf_apf_event); |
| 540 | context->offset = read_mem_params.addr_offset; |
| 541 | |
| 542 | context->buf = bufptr; |
| 543 | context->buf_len = read_mem_params.length; |
| 544 | context->magic = APF_CONTEXT_MAGIC; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 545 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 546 | status = sme_apf_read_work_memory(hdd_adapter_get_mac_handle(adapter), |
Jeff Johnson | c616223 | 2018-06-20 13:33:07 -0700 | [diff] [blame] | 547 | &read_mem_params, |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 548 | hdd_apf_read_memory_callback); |
| 549 | if (QDF_IS_STATUS_ERROR(status)) { |
| 550 | hdd_err("Unable to post sme APF read memory message (status-%d)", |
| 551 | status); |
| 552 | ret = -EINVAL; |
| 553 | goto fail; |
| 554 | } |
| 555 | |
| 556 | /* request was sent -- wait for the response */ |
| 557 | status = qdf_wait_for_event_completion(&context->qdf_apf_event, |
| 558 | WLAN_WAIT_TIME_APF_READ_MEM); |
| 559 | if (QDF_IS_STATUS_ERROR(status)) { |
| 560 | hdd_err("Target response timed out"); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 561 | context->magic = 0; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 562 | ret = -ETIMEDOUT; |
| 563 | goto fail; |
| 564 | } |
| 565 | |
| 566 | nl_buf_len += sizeof(uint32_t) + NLA_HDRLEN; |
| 567 | nl_buf_len += context->buf_len + NLA_HDRLEN; |
| 568 | |
| 569 | skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); |
| 570 | if (!skb) { |
| 571 | hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); |
| 572 | ret = -ENOMEM; |
| 573 | goto fail; |
| 574 | } |
| 575 | |
| 576 | if (nla_put_u32(skb, APF_SUBCMD, QCA_WLAN_READ_PACKET_FILTER) || |
| 577 | nla_put(skb, APF_PROGRAM, read_mem_params.length, context->buf)) { |
| 578 | hdd_err("put fail"); |
| 579 | kfree_skb(skb); |
| 580 | ret = -EINVAL; |
| 581 | goto fail; |
| 582 | } |
| 583 | |
| 584 | cfg80211_vendor_cmd_reply(skb); |
Nachiket Kukade | 338547b | 2019-01-03 18:50:46 +0530 | [diff] [blame^] | 585 | |
| 586 | hdd_debug("Reading APF work memory from offset 0x%X:", |
| 587 | read_mem_params.addr_offset); |
| 588 | QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, |
| 589 | context->buf, read_mem_params.length); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 590 | fail: |
| 591 | if (context->buf) { |
| 592 | qdf_mem_free(context->buf); |
| 593 | context->buf = NULL; |
| 594 | } |
| 595 | |
| 596 | hdd_exit(); |
| 597 | return ret; |
| 598 | } |
| 599 | |
| 600 | /** |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 601 | * wlan_hdd_cfg80211_apf_offload() - Set/Reset to APF Offload |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 602 | * @wiphy: wiphy structure pointer |
| 603 | * @wdev: Wireless device structure pointer |
| 604 | * @data: Pointer to the data received |
| 605 | * @data_len: Length of @data |
| 606 | * |
| 607 | * Return: 0 on success; errno on failure |
| 608 | */ |
| 609 | static int |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 610 | __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 611 | struct wireless_dev *wdev, |
| 612 | const void *data, int data_len) |
| 613 | { |
| 614 | struct hdd_context *hdd_ctx = wiphy_priv(wiphy); |
| 615 | struct net_device *dev = wdev->netdev; |
| 616 | struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 617 | struct nlattr *tb[APF_MAX + 1]; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 618 | int ret_val = 0, apf_subcmd; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 619 | struct hdd_apf_context *context; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 620 | |
| 621 | hdd_enter(); |
| 622 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 623 | if (!adapter) { |
| 624 | hdd_err("Adapter is null"); |
| 625 | return -EINVAL; |
| 626 | } |
| 627 | |
| 628 | context = &adapter->apf_context; |
| 629 | |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 630 | ret_val = wlan_hdd_validate_context(hdd_ctx); |
| 631 | if (ret_val) |
| 632 | return ret_val; |
| 633 | |
| 634 | if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { |
| 635 | hdd_err("Command not allowed in FTM mode"); |
| 636 | return -EINVAL; |
| 637 | } |
| 638 | |
Wu Gao | 66454f1 | 2018-09-26 19:55:41 +0800 | [diff] [blame] | 639 | if (!ucfg_pmo_is_apf_enabled(hdd_ctx->psoc)) { |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 640 | hdd_err("APF is not supported or disabled through INI"); |
| 641 | return -ENOTSUPP; |
| 642 | } |
| 643 | |
| 644 | if (!(adapter->device_mode == QDF_STA_MODE || |
| 645 | adapter->device_mode == QDF_P2P_CLIENT_MODE)) { |
| 646 | hdd_err("APF only supported in STA or P2P CLI modes!"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 647 | return -ENOTSUPP; |
| 648 | } |
| 649 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 650 | if (wlan_cfg80211_nla_parse(tb, APF_MAX, data, data_len, |
| 651 | wlan_hdd_apf_offload_policy)) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 652 | hdd_err("Invalid ATTR"); |
| 653 | return -EINVAL; |
| 654 | } |
| 655 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 656 | if (!tb[APF_SUBCMD]) { |
| 657 | hdd_err("attr apf sub-command failed"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 658 | return -EINVAL; |
| 659 | } |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 660 | apf_subcmd = nla_get_u32(tb[APF_SUBCMD]); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 661 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 662 | /* Do not allow simultaneous new APF commands on the same adapter */ |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 663 | qdf_spin_lock(&context->lock); |
| 664 | if (context->cmd_in_progress) { |
| 665 | qdf_spin_unlock(&context->lock); |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 666 | hdd_err("Another cmd in progress for same session!"); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 667 | return -EAGAIN; |
| 668 | } |
| 669 | context->cmd_in_progress = true; |
| 670 | qdf_spin_unlock(&context->lock); |
| 671 | |
| 672 | switch (apf_subcmd) { |
| 673 | /* Legacy APF sub-commands */ |
| 674 | case QCA_WLAN_SET_PACKET_FILTER: |
| 675 | ret_val = hdd_set_reset_apf_offload(hdd_ctx, tb, |
| 676 | adapter); |
| 677 | break; |
| 678 | case QCA_WLAN_GET_PACKET_FILTER: |
| 679 | ret_val = hdd_get_apf_capabilities(hdd_ctx); |
| 680 | break; |
| 681 | |
| 682 | /* APF 3.0 sub-commands */ |
| 683 | case QCA_WLAN_WRITE_PACKET_FILTER: |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 684 | ret_val = hdd_apf_write_memory(adapter, tb); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 685 | break; |
| 686 | case QCA_WLAN_READ_PACKET_FILTER: |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 687 | ret_val = hdd_apf_read_memory(adapter, tb); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 688 | break; |
| 689 | case QCA_WLAN_ENABLE_PACKET_FILTER: |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 690 | ret_val = hdd_enable_disable_apf(adapter, true); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 691 | break; |
| 692 | case QCA_WLAN_DISABLE_PACKET_FILTER: |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 693 | ret_val = hdd_enable_disable_apf(adapter, false); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 694 | break; |
| 695 | default: |
| 696 | hdd_err("Unknown APF Sub-command: %d", apf_subcmd); |
| 697 | ret_val = -ENOTSUPP; |
| 698 | } |
| 699 | |
| 700 | qdf_spin_lock(&context->lock); |
| 701 | context->cmd_in_progress = false; |
| 702 | qdf_spin_unlock(&context->lock); |
| 703 | |
| 704 | return ret_val; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 705 | } |
| 706 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 707 | int |
| 708 | wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 709 | const void *data, int data_len) |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 710 | { |
| 711 | int ret; |
| 712 | |
| 713 | cds_ssr_protect(__func__); |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 714 | ret = __wlan_hdd_cfg80211_apf_offload(wiphy, wdev, data, data_len); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 715 | cds_ssr_unprotect(__func__); |
| 716 | |
| 717 | return ret; |
| 718 | } |
| 719 | |