Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. |
| 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 | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 224 | struct sir_apf_set_offload *apf_set_offload; |
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 | apf_set_offload = qdf_mem_malloc(sizeof(*apf_set_offload)); |
Min Liu | 74a1a50 | 2018-10-10 19:59:07 +0800 | [diff] [blame^] | 238 | if (!apf_set_offload) |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 239 | return -ENOMEM; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 240 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 241 | /* Parse and fetch apf packet size */ |
| 242 | if (!tb[APF_PACKET_SIZE]) { |
| 243 | hdd_err("attr apf packet size failed"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 244 | ret = -EINVAL; |
| 245 | goto fail; |
| 246 | } |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 247 | apf_set_offload->total_length = nla_get_u32(tb[APF_PACKET_SIZE]); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 248 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 249 | if (!apf_set_offload->total_length) { |
| 250 | hdd_debug("APF reset packet filter received"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 251 | goto post_sme; |
| 252 | } |
| 253 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 254 | /* Parse and fetch apf program */ |
| 255 | if (!tb[APF_PROGRAM]) { |
| 256 | hdd_err("attr apf program failed"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 257 | ret = -EINVAL; |
| 258 | goto fail; |
| 259 | } |
| 260 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 261 | prog_len = nla_len(tb[APF_PROGRAM]); |
| 262 | apf_set_offload->program = qdf_mem_malloc(sizeof(uint8_t) * prog_len); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 263 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 264 | if (!apf_set_offload->program) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 265 | ret = -ENOMEM; |
| 266 | goto fail; |
| 267 | } |
| 268 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 269 | apf_set_offload->current_length = prog_len; |
| 270 | nla_memcpy(apf_set_offload->program, tb[APF_PROGRAM], prog_len); |
| 271 | apf_set_offload->session_id = adapter->session_id; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 272 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 273 | hdd_debug("APF set instructions"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 274 | QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 275 | apf_set_offload->program, prog_len); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 276 | |
| 277 | /* Parse and fetch filter Id */ |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 278 | if (!tb[APF_FILTER_ID]) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 279 | hdd_err("attr filter id failed"); |
| 280 | ret = -EINVAL; |
| 281 | goto fail; |
| 282 | } |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 283 | apf_set_offload->filter_id = nla_get_u32(tb[APF_FILTER_ID]); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 284 | |
| 285 | /* Parse and fetch current offset */ |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 286 | if (!tb[APF_CURRENT_OFFSET]) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 287 | hdd_err("attr current offset failed"); |
| 288 | ret = -EINVAL; |
| 289 | goto fail; |
| 290 | } |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 291 | apf_set_offload->current_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 292 | |
| 293 | post_sme: |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 294 | 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", |
| 295 | apf_set_offload->session_id, apf_set_offload->version, |
| 296 | apf_set_offload->filter_id, apf_set_offload->total_length, |
| 297 | apf_set_offload->current_length, |
| 298 | apf_set_offload->current_offset); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 299 | |
Jeff Johnson | c616223 | 2018-06-20 13:33:07 -0700 | [diff] [blame] | 300 | status = sme_set_apf_instructions(hdd_ctx->mac_handle, apf_set_offload); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 301 | if (!QDF_IS_STATUS_SUCCESS(status)) { |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 302 | hdd_err("sme_set_apf_instructions failed(err=%d)", status); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 303 | ret = -EINVAL; |
| 304 | goto fail; |
| 305 | } |
| 306 | hdd_exit(); |
| 307 | |
| 308 | fail: |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 309 | if (apf_set_offload->current_length) |
| 310 | qdf_mem_free(apf_set_offload->program); |
| 311 | qdf_mem_free(apf_set_offload); |
Rajeev Kumar Sirasanagandla | 85f8b02 | 2018-03-12 12:52:59 +0530 | [diff] [blame] | 312 | |
| 313 | if (!ret) |
| 314 | hdd_ctx->apf_enabled_v2 = true; |
| 315 | |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 316 | return ret; |
| 317 | } |
| 318 | |
| 319 | /** |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 320 | * hdd_enable_disable_apf - Enable or Disable the APF interpreter |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 321 | * @adapter: HDD Adapter |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 322 | * @apf_enable: true: Enable APF Int., false: disable APF Int. |
| 323 | * |
| 324 | * Return: 0 on success, errno on failure |
| 325 | */ |
| 326 | static int |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 327 | hdd_enable_disable_apf(struct hdd_adapter *adapter, bool apf_enable) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 328 | { |
| 329 | QDF_STATUS status; |
| 330 | |
| 331 | hdd_enter(); |
| 332 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 333 | status = sme_set_apf_enable_disable(hdd_adapter_get_mac_handle(adapter), |
| 334 | adapter->session_id, apf_enable); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 335 | if (!QDF_IS_STATUS_SUCCESS(status)) { |
| 336 | hdd_err("Unable to post sme apf enable/disable message (status-%d)", |
| 337 | status); |
| 338 | return -EINVAL; |
| 339 | } |
| 340 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 341 | adapter->apf_context.apf_enabled = apf_enable; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 342 | |
| 343 | hdd_exit(); |
| 344 | return 0; |
| 345 | } |
| 346 | |
| 347 | /** |
| 348 | * hdd_apf_write_memory - Write into the apf work memory |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 349 | * @adapter: HDD Adapter |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 350 | * @tb: list of attributes |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 351 | * |
| 352 | * This function writes code/data into the APF work memory and |
| 353 | * provides program length that is passed on to the interpreter. |
| 354 | * |
| 355 | * Return: 0 on success, errno on failure |
| 356 | */ |
| 357 | static int |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 358 | hdd_apf_write_memory(struct hdd_adapter *adapter, struct nlattr **tb) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 359 | { |
| 360 | struct wmi_apf_write_memory_params write_mem_params = {0}; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 361 | struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 362 | QDF_STATUS status; |
| 363 | int ret = 0; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 364 | |
| 365 | hdd_enter(); |
| 366 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 367 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 368 | write_mem_params.vdev_id = adapter->session_id; |
| 369 | if (adapter->apf_context.apf_enabled) { |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 370 | hdd_err("Cannot get/set when APF interpreter is enabled"); |
| 371 | return -EINVAL; |
| 372 | } |
| 373 | |
| 374 | /* Read program length */ |
| 375 | if (!tb[APF_PROG_LEN]) { |
| 376 | hdd_err("attr program length failed"); |
| 377 | return -EINVAL; |
| 378 | } |
| 379 | write_mem_params.program_len = nla_get_u32(tb[APF_PROG_LEN]); |
| 380 | |
| 381 | /* Read APF work memory offset */ |
| 382 | if (!tb[APF_CURRENT_OFFSET]) { |
| 383 | hdd_err("attr apf packet size failed"); |
| 384 | return -EINVAL; |
| 385 | } |
| 386 | write_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); |
| 387 | |
| 388 | /* Parse and fetch apf program */ |
| 389 | if (!tb[APF_PROGRAM]) { |
| 390 | hdd_err("attr apf program failed"); |
| 391 | return -EINVAL; |
| 392 | } |
| 393 | |
| 394 | write_mem_params.length = nla_len(tb[APF_PROGRAM]); |
| 395 | if (!write_mem_params.length) { |
| 396 | hdd_err("Program attr with empty data"); |
| 397 | return -EINVAL; |
| 398 | } |
| 399 | |
| 400 | write_mem_params.buf = qdf_mem_malloc(sizeof(uint8_t) |
| 401 | * write_mem_params.length); |
Min Liu | 74a1a50 | 2018-10-10 19:59:07 +0800 | [diff] [blame^] | 402 | if (!write_mem_params.buf) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 403 | return -EINVAL; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 404 | nla_memcpy(write_mem_params.buf, tb[APF_PROGRAM], |
| 405 | write_mem_params.length); |
| 406 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 407 | write_mem_params.apf_version = hdd_ctx->apf_version; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 408 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 409 | status = sme_apf_write_work_memory(hdd_adapter_get_mac_handle(adapter), |
Jeff Johnson | c616223 | 2018-06-20 13:33:07 -0700 | [diff] [blame] | 410 | &write_mem_params); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 411 | if (!QDF_IS_STATUS_SUCCESS(status)) { |
| 412 | hdd_err("Unable to retrieve APF caps"); |
| 413 | ret = -EINVAL; |
| 414 | } |
| 415 | |
| 416 | if (write_mem_params.buf) |
| 417 | qdf_mem_free(write_mem_params.buf); |
| 418 | |
| 419 | hdd_exit(); |
| 420 | return ret; |
| 421 | } |
| 422 | |
| 423 | /** |
| 424 | * hdd_apf_read_memory_callback - HDD Callback for the APF read memory |
| 425 | * operation |
| 426 | * @context: Hdd context |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 427 | * @evt: APF read memory event response parameters |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 428 | * |
| 429 | * Return: 0 on success, errno on failure |
| 430 | */ |
| 431 | static void |
| 432 | hdd_apf_read_memory_callback(void *hdd_context, |
| 433 | struct wmi_apf_read_memory_resp_event_params *evt) |
| 434 | { |
| 435 | struct hdd_context *hdd_ctx = hdd_context; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 436 | struct hdd_adapter *adapter; |
| 437 | struct hdd_apf_context *context; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 438 | uint8_t *buf_ptr; |
| 439 | uint32_t pkt_offset; |
| 440 | |
| 441 | hdd_enter(); |
| 442 | |
| 443 | if (wlan_hdd_validate_context(hdd_ctx) || !evt) { |
| 444 | hdd_err("HDD context is invalid or event buf(%pK) is null", |
| 445 | evt); |
| 446 | return; |
| 447 | } |
| 448 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 449 | adapter = hdd_get_adapter_by_vdev(hdd_ctx, evt->vdev_id); |
Ashish Kumar Dhanotiya | 04cc7c2 | 2018-05-11 14:43:10 +0530 | [diff] [blame] | 450 | if (hdd_validate_adapter(adapter)) |
| 451 | return; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 452 | context = &adapter->apf_context; |
| 453 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 454 | if (context->magic != APF_CONTEXT_MAGIC) { |
| 455 | /* The caller presumably timed out, nothing to do */ |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 456 | hdd_err("Caller timed out or corrupt magic, simply return"); |
| 457 | return; |
| 458 | } |
| 459 | |
| 460 | if (evt->offset < context->offset) { |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 461 | hdd_err("Offset in read event(%d) smaller than offset in request(%d)!", |
| 462 | evt->offset, context->offset); |
| 463 | return; |
| 464 | } |
| 465 | |
| 466 | /* |
| 467 | * offset in the event is relative to the APF work memory. |
| 468 | * Calculate the packet offset, which gives us the relative |
| 469 | * location in the buffer to start copy into. |
| 470 | */ |
| 471 | pkt_offset = evt->offset - context->offset; |
| 472 | |
| 473 | if (context->buf_len < pkt_offset + evt->length) { |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 474 | hdd_err("Read chunk exceeding allocated space"); |
| 475 | return; |
| 476 | } |
| 477 | buf_ptr = context->buf + pkt_offset; |
| 478 | |
| 479 | qdf_mem_copy(buf_ptr, evt->data, evt->length); |
| 480 | |
| 481 | if (!evt->more_data) { |
| 482 | /* Release the caller after last event, clear magic */ |
| 483 | context->magic = 0; |
| 484 | qdf_event_set(&context->qdf_apf_event); |
| 485 | } |
| 486 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 487 | hdd_exit(); |
| 488 | } |
| 489 | |
| 490 | /** |
| 491 | * hdd_apf_read_memory - Read part of the apf work memory |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 492 | * @adapter: HDD Adapter |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 493 | * @tb: list of attributes |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 494 | * |
| 495 | * Return: 0 on success, errno on failure |
| 496 | */ |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 497 | 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] | 498 | { |
| 499 | struct wmi_apf_read_memory_params read_mem_params = {0}; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 500 | struct hdd_apf_context *context = &adapter->apf_context; |
| 501 | struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 502 | QDF_STATUS status; |
| 503 | unsigned long nl_buf_len = NLMSG_HDRLEN; |
| 504 | int ret = 0; |
| 505 | struct sk_buff *skb = NULL; |
| 506 | uint8_t *bufptr; |
| 507 | |
| 508 | hdd_enter(); |
| 509 | |
Rajeev Kumar | 75fc36e | 2018-09-04 11:41:10 -0700 | [diff] [blame] | 510 | if (context->apf_enabled) { |
| 511 | hdd_err("Cannot get/set while interpreter is enabled"); |
| 512 | return -EINVAL; |
| 513 | } |
| 514 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 515 | read_mem_params.vdev_id = adapter->session_id; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 516 | |
| 517 | /* Read APF work memory offset */ |
| 518 | if (!tb[APF_CURRENT_OFFSET]) { |
| 519 | hdd_err("attr apf memory offset failed"); |
| 520 | return -EINVAL; |
| 521 | } |
| 522 | read_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); |
| 523 | |
| 524 | /* Read length */ |
| 525 | if (!tb[APF_PACKET_SIZE]) { |
| 526 | hdd_err("attr apf packet size failed"); |
| 527 | return -EINVAL; |
| 528 | } |
| 529 | read_mem_params.length = nla_get_u32(tb[APF_PACKET_SIZE]); |
| 530 | if (!read_mem_params.length) { |
| 531 | hdd_err("apf read length cannot be zero!"); |
| 532 | return -EINVAL; |
| 533 | } |
| 534 | bufptr = qdf_mem_malloc(read_mem_params.length); |
Min Liu | 74a1a50 | 2018-10-10 19:59:07 +0800 | [diff] [blame^] | 535 | if (!bufptr) |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 536 | return -ENOMEM; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 537 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 538 | qdf_event_reset(&context->qdf_apf_event); |
| 539 | context->offset = read_mem_params.addr_offset; |
| 540 | |
| 541 | context->buf = bufptr; |
| 542 | context->buf_len = read_mem_params.length; |
| 543 | context->magic = APF_CONTEXT_MAGIC; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 544 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 545 | status = sme_apf_read_work_memory(hdd_adapter_get_mac_handle(adapter), |
Jeff Johnson | c616223 | 2018-06-20 13:33:07 -0700 | [diff] [blame] | 546 | &read_mem_params, |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 547 | hdd_apf_read_memory_callback); |
| 548 | if (QDF_IS_STATUS_ERROR(status)) { |
| 549 | hdd_err("Unable to post sme APF read memory message (status-%d)", |
| 550 | status); |
| 551 | ret = -EINVAL; |
| 552 | goto fail; |
| 553 | } |
| 554 | |
| 555 | /* request was sent -- wait for the response */ |
| 556 | status = qdf_wait_for_event_completion(&context->qdf_apf_event, |
| 557 | WLAN_WAIT_TIME_APF_READ_MEM); |
| 558 | if (QDF_IS_STATUS_ERROR(status)) { |
| 559 | hdd_err("Target response timed out"); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 560 | context->magic = 0; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 561 | ret = -ETIMEDOUT; |
| 562 | goto fail; |
| 563 | } |
| 564 | |
| 565 | nl_buf_len += sizeof(uint32_t) + NLA_HDRLEN; |
| 566 | nl_buf_len += context->buf_len + NLA_HDRLEN; |
| 567 | |
| 568 | skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); |
| 569 | if (!skb) { |
| 570 | hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); |
| 571 | ret = -ENOMEM; |
| 572 | goto fail; |
| 573 | } |
| 574 | |
| 575 | if (nla_put_u32(skb, APF_SUBCMD, QCA_WLAN_READ_PACKET_FILTER) || |
| 576 | nla_put(skb, APF_PROGRAM, read_mem_params.length, context->buf)) { |
| 577 | hdd_err("put fail"); |
| 578 | kfree_skb(skb); |
| 579 | ret = -EINVAL; |
| 580 | goto fail; |
| 581 | } |
| 582 | |
| 583 | cfg80211_vendor_cmd_reply(skb); |
| 584 | fail: |
| 585 | if (context->buf) { |
| 586 | qdf_mem_free(context->buf); |
| 587 | context->buf = NULL; |
| 588 | } |
| 589 | |
| 590 | hdd_exit(); |
| 591 | return ret; |
| 592 | } |
| 593 | |
| 594 | /** |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 595 | * wlan_hdd_cfg80211_apf_offload() - Set/Reset to APF Offload |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 596 | * @wiphy: wiphy structure pointer |
| 597 | * @wdev: Wireless device structure pointer |
| 598 | * @data: Pointer to the data received |
| 599 | * @data_len: Length of @data |
| 600 | * |
| 601 | * Return: 0 on success; errno on failure |
| 602 | */ |
| 603 | static int |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 604 | __wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 605 | struct wireless_dev *wdev, |
| 606 | const void *data, int data_len) |
| 607 | { |
| 608 | struct hdd_context *hdd_ctx = wiphy_priv(wiphy); |
| 609 | struct net_device *dev = wdev->netdev; |
| 610 | struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 611 | struct nlattr *tb[APF_MAX + 1]; |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 612 | int ret_val = 0, apf_subcmd; |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 613 | struct hdd_apf_context *context; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 614 | |
| 615 | hdd_enter(); |
| 616 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 617 | if (!adapter) { |
| 618 | hdd_err("Adapter is null"); |
| 619 | return -EINVAL; |
| 620 | } |
| 621 | |
| 622 | context = &adapter->apf_context; |
| 623 | |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 624 | ret_val = wlan_hdd_validate_context(hdd_ctx); |
| 625 | if (ret_val) |
| 626 | return ret_val; |
| 627 | |
| 628 | if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { |
| 629 | hdd_err("Command not allowed in FTM mode"); |
| 630 | return -EINVAL; |
| 631 | } |
| 632 | |
Wu Gao | 66454f1 | 2018-09-26 19:55:41 +0800 | [diff] [blame] | 633 | if (!ucfg_pmo_is_apf_enabled(hdd_ctx->psoc)) { |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 634 | hdd_err("APF is not supported or disabled through INI"); |
| 635 | return -ENOTSUPP; |
| 636 | } |
| 637 | |
| 638 | if (!(adapter->device_mode == QDF_STA_MODE || |
| 639 | adapter->device_mode == QDF_P2P_CLIENT_MODE)) { |
| 640 | hdd_err("APF only supported in STA or P2P CLI modes!"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 641 | return -ENOTSUPP; |
| 642 | } |
| 643 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 644 | if (wlan_cfg80211_nla_parse(tb, APF_MAX, data, data_len, |
| 645 | wlan_hdd_apf_offload_policy)) { |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 646 | hdd_err("Invalid ATTR"); |
| 647 | return -EINVAL; |
| 648 | } |
| 649 | |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 650 | if (!tb[APF_SUBCMD]) { |
| 651 | hdd_err("attr apf sub-command failed"); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 652 | return -EINVAL; |
| 653 | } |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 654 | apf_subcmd = nla_get_u32(tb[APF_SUBCMD]); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 655 | |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 656 | /* Do not allow simultaneous new APF commands on the same adapter */ |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 657 | qdf_spin_lock(&context->lock); |
| 658 | if (context->cmd_in_progress) { |
| 659 | qdf_spin_unlock(&context->lock); |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 660 | hdd_err("Another cmd in progress for same session!"); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 661 | return -EAGAIN; |
| 662 | } |
| 663 | context->cmd_in_progress = true; |
| 664 | qdf_spin_unlock(&context->lock); |
| 665 | |
| 666 | switch (apf_subcmd) { |
| 667 | /* Legacy APF sub-commands */ |
| 668 | case QCA_WLAN_SET_PACKET_FILTER: |
| 669 | ret_val = hdd_set_reset_apf_offload(hdd_ctx, tb, |
| 670 | adapter); |
| 671 | break; |
| 672 | case QCA_WLAN_GET_PACKET_FILTER: |
| 673 | ret_val = hdd_get_apf_capabilities(hdd_ctx); |
| 674 | break; |
| 675 | |
| 676 | /* APF 3.0 sub-commands */ |
| 677 | case QCA_WLAN_WRITE_PACKET_FILTER: |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 678 | ret_val = hdd_apf_write_memory(adapter, tb); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 679 | break; |
| 680 | case QCA_WLAN_READ_PACKET_FILTER: |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 681 | ret_val = hdd_apf_read_memory(adapter, tb); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 682 | break; |
| 683 | case QCA_WLAN_ENABLE_PACKET_FILTER: |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 684 | ret_val = hdd_enable_disable_apf(adapter, true); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 685 | break; |
| 686 | case QCA_WLAN_DISABLE_PACKET_FILTER: |
Nachiket Kukade | 5f0ce4f | 2018-06-15 19:47:37 +0530 | [diff] [blame] | 687 | ret_val = hdd_enable_disable_apf(adapter, false); |
Nachiket Kukade | 177b5b0 | 2018-05-22 20:52:17 +0530 | [diff] [blame] | 688 | break; |
| 689 | default: |
| 690 | hdd_err("Unknown APF Sub-command: %d", apf_subcmd); |
| 691 | ret_val = -ENOTSUPP; |
| 692 | } |
| 693 | |
| 694 | qdf_spin_lock(&context->lock); |
| 695 | context->cmd_in_progress = false; |
| 696 | qdf_spin_unlock(&context->lock); |
| 697 | |
| 698 | return ret_val; |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 699 | } |
| 700 | |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 701 | int |
| 702 | wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 703 | const void *data, int data_len) |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 704 | { |
| 705 | int ret; |
| 706 | |
| 707 | cds_ssr_protect(__func__); |
Nachiket Kukade | e547a48 | 2018-05-22 16:43:30 +0530 | [diff] [blame] | 708 | ret = __wlan_hdd_cfg80211_apf_offload(wiphy, wdev, data, data_len); |
Nachiket Kukade | d0dd62e | 2018-05-21 18:39:22 +0530 | [diff] [blame] | 709 | cds_ssr_unprotect(__func__); |
| 710 | |
| 711 | return ret; |
| 712 | } |
| 713 | |