| .. | .. |
|---|
| 1 | | -/* |
|---|
| 2 | | - * Copyright (c) 2015-2016 Quantenna Communications, Inc. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or |
|---|
| 5 | | - * modify it under the terms of the GNU General Public License |
|---|
| 6 | | - * as published by the Free Software Foundation; either version 2 |
|---|
| 7 | | - * of the License, or (at your option) any later version. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 10 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 | | - * GNU General Public License for more details. |
|---|
| 13 | | - * |
|---|
| 14 | | - */ |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
|---|
| 2 | +/* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */ |
|---|
| 15 | 3 | |
|---|
| 16 | 4 | #include <linux/types.h> |
|---|
| 17 | 5 | #include <linux/skbuff.h> |
|---|
| .. | .. |
|---|
| 22 | 10 | #include "qlink_util.h" |
|---|
| 23 | 11 | #include "bus.h" |
|---|
| 24 | 12 | #include "commands.h" |
|---|
| 13 | + |
|---|
| 14 | +/* Let device itself to select best values for current conditions */ |
|---|
| 15 | +#define QTNF_SCAN_TIME_AUTO 0 |
|---|
| 16 | + |
|---|
| 17 | +#define QTNF_SCAN_DWELL_ACTIVE_DEFAULT 90 |
|---|
| 18 | +#define QTNF_SCAN_DWELL_PASSIVE_DEFAULT 100 |
|---|
| 19 | +#define QTNF_SCAN_SAMPLE_DURATION_DEFAULT QTNF_SCAN_TIME_AUTO |
|---|
| 25 | 20 | |
|---|
| 26 | 21 | static int qtnf_cmd_check_reply_header(const struct qlink_resp *resp, |
|---|
| 27 | 22 | u16 cmd_id, u8 mac_id, u8 vif_id, |
|---|
| .. | .. |
|---|
| 72 | 67 | return -EADDRINUSE; |
|---|
| 73 | 68 | case QLINK_CMD_RESULT_EADDRNOTAVAIL: |
|---|
| 74 | 69 | return -EADDRNOTAVAIL; |
|---|
| 70 | + case QLINK_CMD_RESULT_EBUSY: |
|---|
| 71 | + return -EBUSY; |
|---|
| 75 | 72 | default: |
|---|
| 76 | 73 | return -EFAULT; |
|---|
| 77 | 74 | } |
|---|
| .. | .. |
|---|
| 80 | 77 | static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, |
|---|
| 81 | 78 | struct sk_buff *cmd_skb, |
|---|
| 82 | 79 | struct sk_buff **response_skb, |
|---|
| 83 | | - u16 *result_code, |
|---|
| 84 | 80 | size_t const_resp_size, |
|---|
| 85 | 81 | size_t *var_resp_size) |
|---|
| 86 | 82 | { |
|---|
| 87 | 83 | struct qlink_cmd *cmd; |
|---|
| 88 | | - const struct qlink_resp *resp; |
|---|
| 84 | + struct qlink_resp *resp = NULL; |
|---|
| 89 | 85 | struct sk_buff *resp_skb = NULL; |
|---|
| 86 | + int resp_res = 0; |
|---|
| 90 | 87 | u16 cmd_id; |
|---|
| 91 | | - u8 mac_id, vif_id; |
|---|
| 88 | + u8 mac_id; |
|---|
| 89 | + u8 vif_id; |
|---|
| 92 | 90 | int ret; |
|---|
| 93 | 91 | |
|---|
| 94 | 92 | cmd = (struct qlink_cmd *)cmd_skb->data; |
|---|
| .. | .. |
|---|
| 97 | 95 | vif_id = cmd->vifid; |
|---|
| 98 | 96 | cmd->mhdr.len = cpu_to_le16(cmd_skb->len); |
|---|
| 99 | 97 | |
|---|
| 100 | | - if (unlikely(bus->fw_state != QTNF_FW_STATE_ACTIVE && |
|---|
| 101 | | - le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT)) { |
|---|
| 98 | + pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, cmd_id); |
|---|
| 99 | + |
|---|
| 100 | + if (!qtnf_fw_is_up(bus) && cmd_id != QLINK_CMD_FW_INIT) { |
|---|
| 102 | 101 | pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n", |
|---|
| 103 | | - mac_id, vif_id, le16_to_cpu(cmd->cmd_id), |
|---|
| 104 | | - bus->fw_state); |
|---|
| 102 | + mac_id, vif_id, cmd_id, bus->fw_state); |
|---|
| 105 | 103 | dev_kfree_skb(cmd_skb); |
|---|
| 106 | 104 | return -ENODEV; |
|---|
| 107 | 105 | } |
|---|
| 108 | 106 | |
|---|
| 109 | | - pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, |
|---|
| 110 | | - le16_to_cpu(cmd->cmd_id)); |
|---|
| 111 | | - |
|---|
| 112 | 107 | ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb); |
|---|
| 113 | | - |
|---|
| 114 | | - if (unlikely(ret)) |
|---|
| 108 | + if (ret) |
|---|
| 115 | 109 | goto out; |
|---|
| 116 | 110 | |
|---|
| 117 | | - resp = (const struct qlink_resp *)resp_skb->data; |
|---|
| 111 | + if (WARN_ON(!resp_skb || !resp_skb->data)) { |
|---|
| 112 | + ret = -EFAULT; |
|---|
| 113 | + goto out; |
|---|
| 114 | + } |
|---|
| 115 | + |
|---|
| 116 | + resp = (struct qlink_resp *)resp_skb->data; |
|---|
| 117 | + resp_res = le16_to_cpu(resp->result); |
|---|
| 118 | 118 | ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id, |
|---|
| 119 | 119 | const_resp_size); |
|---|
| 120 | | - |
|---|
| 121 | | - if (unlikely(ret)) |
|---|
| 120 | + if (ret) |
|---|
| 122 | 121 | goto out; |
|---|
| 123 | | - |
|---|
| 124 | | - if (likely(result_code)) |
|---|
| 125 | | - *result_code = le16_to_cpu(resp->result); |
|---|
| 126 | 122 | |
|---|
| 127 | 123 | /* Return length of variable part of response */ |
|---|
| 128 | 124 | if (response_skb && var_resp_size) |
|---|
| .. | .. |
|---|
| 134 | 130 | else |
|---|
| 135 | 131 | consume_skb(resp_skb); |
|---|
| 136 | 132 | |
|---|
| 133 | + if (!ret) |
|---|
| 134 | + return qtnf_cmd_resp_result_decode(resp_res); |
|---|
| 135 | + |
|---|
| 136 | + pr_warn("VIF%u.%u: cmd 0x%.4X failed: %d\n", |
|---|
| 137 | + mac_id, vif_id, cmd_id, ret); |
|---|
| 138 | + |
|---|
| 137 | 139 | return ret; |
|---|
| 138 | 140 | } |
|---|
| 139 | 141 | |
|---|
| 140 | | -static inline int qtnf_cmd_send(struct qtnf_bus *bus, |
|---|
| 141 | | - struct sk_buff *cmd_skb, |
|---|
| 142 | | - u16 *result_code) |
|---|
| 142 | +static inline int qtnf_cmd_send(struct qtnf_bus *bus, struct sk_buff *cmd_skb) |
|---|
| 143 | 143 | { |
|---|
| 144 | | - return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, result_code, |
|---|
| 144 | + return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, |
|---|
| 145 | 145 | sizeof(struct qlink_resp), NULL); |
|---|
| 146 | 146 | } |
|---|
| 147 | 147 | |
|---|
| .. | .. |
|---|
| 175 | 175 | { |
|---|
| 176 | 176 | struct qlink_tlv_ie_set *tlv; |
|---|
| 177 | 177 | |
|---|
| 178 | | - tlv = (struct qlink_tlv_ie_set *)skb_put(cmd_skb, sizeof(*tlv) + len); |
|---|
| 178 | + tlv = (struct qlink_tlv_ie_set *)skb_put(cmd_skb, sizeof(*tlv) + |
|---|
| 179 | + round_up(len, QLINK_ALIGN)); |
|---|
| 179 | 180 | tlv->hdr.type = cpu_to_le16(QTN_TLV_ID_IE_SET); |
|---|
| 180 | 181 | tlv->hdr.len = cpu_to_le16(len + sizeof(*tlv) - sizeof(tlv->hdr)); |
|---|
| 181 | 182 | tlv->type = frame_type; |
|---|
| .. | .. |
|---|
| 185 | 186 | memcpy(tlv->ie_data, buf, len); |
|---|
| 186 | 187 | } |
|---|
| 187 | 188 | |
|---|
| 188 | | -static inline size_t qtnf_cmd_acl_data_size(const struct cfg80211_acl_data *acl) |
|---|
| 189 | | -{ |
|---|
| 190 | | - size_t size = sizeof(struct qlink_acl_data) + |
|---|
| 191 | | - acl->n_acl_entries * sizeof(struct qlink_mac_address); |
|---|
| 192 | | - |
|---|
| 193 | | - return size; |
|---|
| 194 | | -} |
|---|
| 195 | | - |
|---|
| 196 | 189 | static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif, |
|---|
| 197 | 190 | const struct cfg80211_ap_settings *s) |
|---|
| 198 | 191 | { |
|---|
| 199 | 192 | unsigned int len = sizeof(struct qlink_cmd_start_ap); |
|---|
| 200 | 193 | |
|---|
| 201 | | - len += s->ssid_len; |
|---|
| 202 | | - len += s->beacon.head_len; |
|---|
| 203 | | - len += s->beacon.tail_len; |
|---|
| 204 | | - len += s->beacon.beacon_ies_len; |
|---|
| 205 | | - len += s->beacon.proberesp_ies_len; |
|---|
| 206 | | - len += s->beacon.assocresp_ies_len; |
|---|
| 207 | | - len += s->beacon.probe_resp_len; |
|---|
| 194 | + len += round_up(s->ssid_len, QLINK_ALIGN); |
|---|
| 195 | + len += round_up(s->beacon.head_len, QLINK_ALIGN); |
|---|
| 196 | + len += round_up(s->beacon.tail_len, QLINK_ALIGN); |
|---|
| 197 | + len += round_up(s->beacon.beacon_ies_len, QLINK_ALIGN); |
|---|
| 198 | + len += round_up(s->beacon.proberesp_ies_len, QLINK_ALIGN); |
|---|
| 199 | + len += round_up(s->beacon.assocresp_ies_len, QLINK_ALIGN); |
|---|
| 200 | + len += round_up(s->beacon.probe_resp_len, QLINK_ALIGN); |
|---|
| 208 | 201 | |
|---|
| 209 | 202 | if (cfg80211_chandef_valid(&s->chandef)) |
|---|
| 210 | 203 | len += sizeof(struct qlink_tlv_chandef); |
|---|
| 211 | 204 | |
|---|
| 212 | | - if (s->acl) |
|---|
| 205 | + if (s->acl) { |
|---|
| 206 | + unsigned int acl_len = struct_size(s->acl, mac_addrs, |
|---|
| 207 | + s->acl->n_acl_entries); |
|---|
| 208 | + |
|---|
| 213 | 209 | len += sizeof(struct qlink_tlv_hdr) + |
|---|
| 214 | | - qtnf_cmd_acl_data_size(s->acl); |
|---|
| 210 | + round_up(acl_len, QLINK_ALIGN); |
|---|
| 211 | + } |
|---|
| 215 | 212 | |
|---|
| 216 | 213 | if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) { |
|---|
| 217 | 214 | pr_err("VIF%u.%u: can not fit AP settings: %u\n", |
|---|
| .. | .. |
|---|
| 222 | 219 | return true; |
|---|
| 223 | 220 | } |
|---|
| 224 | 221 | |
|---|
| 222 | +static void qtnf_cmd_tlv_ie_ext_add(struct sk_buff *cmd_skb, u8 eid_ext, |
|---|
| 223 | + const void *buf, size_t len) |
|---|
| 224 | +{ |
|---|
| 225 | + struct qlink_tlv_ext_ie *tlv; |
|---|
| 226 | + |
|---|
| 227 | + tlv = (struct qlink_tlv_ext_ie *)skb_put(cmd_skb, sizeof(*tlv) + len); |
|---|
| 228 | + tlv->hdr.type = cpu_to_le16(WLAN_EID_EXTENSION); |
|---|
| 229 | + tlv->hdr.len = cpu_to_le16(sizeof(*tlv) + len - sizeof(tlv->hdr)); |
|---|
| 230 | + tlv->eid_ext = eid_ext; |
|---|
| 231 | + |
|---|
| 232 | + if (len && buf) |
|---|
| 233 | + memcpy(tlv->ie_data, buf, len); |
|---|
| 234 | +} |
|---|
| 235 | + |
|---|
| 225 | 236 | int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, |
|---|
| 226 | 237 | const struct cfg80211_ap_settings *s) |
|---|
| 227 | 238 | { |
|---|
| 228 | 239 | struct sk_buff *cmd_skb; |
|---|
| 229 | 240 | struct qlink_cmd_start_ap *cmd; |
|---|
| 230 | 241 | struct qlink_auth_encr *aen; |
|---|
| 231 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 232 | 242 | int ret; |
|---|
| 233 | 243 | int i; |
|---|
| 234 | 244 | |
|---|
| .. | .. |
|---|
| 252 | 262 | cmd->pbss = s->pbss; |
|---|
| 253 | 263 | cmd->ht_required = s->ht_required; |
|---|
| 254 | 264 | cmd->vht_required = s->vht_required; |
|---|
| 265 | + cmd->twt_responder = s->twt_responder; |
|---|
| 266 | + if (s->he_obss_pd.enable) { |
|---|
| 267 | + cmd->sr_params.sr_control |= QLINK_SR_SRG_INFORMATION_PRESENT; |
|---|
| 268 | + cmd->sr_params.srg_obss_pd_min_offset = |
|---|
| 269 | + s->he_obss_pd.min_offset; |
|---|
| 270 | + cmd->sr_params.srg_obss_pd_max_offset = |
|---|
| 271 | + s->he_obss_pd.max_offset; |
|---|
| 272 | + } |
|---|
| 255 | 273 | |
|---|
| 256 | 274 | aen = &cmd->aen; |
|---|
| 257 | 275 | aen->auth_type = s->auth_type; |
|---|
| .. | .. |
|---|
| 302 | 320 | |
|---|
| 303 | 321 | if (s->ht_cap) { |
|---|
| 304 | 322 | struct qlink_tlv_hdr *tlv = (struct qlink_tlv_hdr *) |
|---|
| 305 | | - skb_put(cmd_skb, sizeof(*tlv) + sizeof(*s->ht_cap)); |
|---|
| 323 | + skb_put(cmd_skb, sizeof(*tlv) + |
|---|
| 324 | + round_up(sizeof(*s->ht_cap), QLINK_ALIGN)); |
|---|
| 306 | 325 | |
|---|
| 307 | 326 | tlv->type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); |
|---|
| 308 | 327 | tlv->len = cpu_to_le16(sizeof(*s->ht_cap)); |
|---|
| .. | .. |
|---|
| 318 | 337 | memcpy(tlv->val, s->vht_cap, sizeof(*s->vht_cap)); |
|---|
| 319 | 338 | } |
|---|
| 320 | 339 | |
|---|
| 340 | + if (s->he_cap) |
|---|
| 341 | + qtnf_cmd_tlv_ie_ext_add(cmd_skb, WLAN_EID_EXT_HE_CAPABILITY, |
|---|
| 342 | + s->he_cap, sizeof(*s->he_cap)); |
|---|
| 343 | + |
|---|
| 321 | 344 | if (s->acl) { |
|---|
| 322 | | - size_t acl_size = qtnf_cmd_acl_data_size(s->acl); |
|---|
| 345 | + size_t acl_size = struct_size(s->acl, mac_addrs, |
|---|
| 346 | + s->acl->n_acl_entries); |
|---|
| 323 | 347 | struct qlink_tlv_hdr *tlv = |
|---|
| 324 | | - skb_put(cmd_skb, sizeof(*tlv) + acl_size); |
|---|
| 348 | + skb_put(cmd_skb, |
|---|
| 349 | + sizeof(*tlv) + round_up(acl_size, QLINK_ALIGN)); |
|---|
| 325 | 350 | |
|---|
| 326 | 351 | tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA); |
|---|
| 327 | 352 | tlv->len = cpu_to_le16(acl_size); |
|---|
| .. | .. |
|---|
| 329 | 354 | } |
|---|
| 330 | 355 | |
|---|
| 331 | 356 | qtnf_bus_lock(vif->mac->bus); |
|---|
| 332 | | - |
|---|
| 333 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 334 | | - |
|---|
| 335 | | - if (unlikely(ret)) |
|---|
| 357 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 358 | + if (ret) |
|---|
| 336 | 359 | goto out; |
|---|
| 337 | | - |
|---|
| 338 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 339 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 340 | | - vif->vifid, res_code); |
|---|
| 341 | | - ret = -EFAULT; |
|---|
| 342 | | - goto out; |
|---|
| 343 | | - } |
|---|
| 344 | 360 | |
|---|
| 345 | 361 | netif_carrier_on(vif->netdev); |
|---|
| 346 | 362 | |
|---|
| 347 | 363 | out: |
|---|
| 348 | 364 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 365 | + |
|---|
| 349 | 366 | return ret; |
|---|
| 350 | 367 | } |
|---|
| 351 | 368 | |
|---|
| 352 | 369 | int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif) |
|---|
| 353 | 370 | { |
|---|
| 354 | 371 | struct sk_buff *cmd_skb; |
|---|
| 355 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 356 | 372 | int ret; |
|---|
| 357 | 373 | |
|---|
| 358 | 374 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 362 | 378 | return -ENOMEM; |
|---|
| 363 | 379 | |
|---|
| 364 | 380 | qtnf_bus_lock(vif->mac->bus); |
|---|
| 365 | | - |
|---|
| 366 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 367 | | - |
|---|
| 368 | | - if (unlikely(ret)) |
|---|
| 381 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 382 | + if (ret) |
|---|
| 369 | 383 | goto out; |
|---|
| 370 | | - |
|---|
| 371 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 372 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 373 | | - vif->vifid, res_code); |
|---|
| 374 | | - ret = -EFAULT; |
|---|
| 375 | | - goto out; |
|---|
| 376 | | - } |
|---|
| 377 | | - |
|---|
| 378 | | - netif_carrier_off(vif->netdev); |
|---|
| 379 | 384 | |
|---|
| 380 | 385 | out: |
|---|
| 381 | 386 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 387 | + |
|---|
| 382 | 388 | return ret; |
|---|
| 383 | 389 | } |
|---|
| 384 | 390 | |
|---|
| .. | .. |
|---|
| 386 | 392 | { |
|---|
| 387 | 393 | struct sk_buff *cmd_skb; |
|---|
| 388 | 394 | struct qlink_cmd_mgmt_frame_register *cmd; |
|---|
| 389 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 390 | 395 | int ret; |
|---|
| 391 | 396 | |
|---|
| 392 | 397 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 401 | 406 | cmd->frame_type = cpu_to_le16(frame_type); |
|---|
| 402 | 407 | cmd->do_register = reg; |
|---|
| 403 | 408 | |
|---|
| 404 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 405 | | - |
|---|
| 406 | | - if (unlikely(ret)) |
|---|
| 409 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 410 | + if (ret) |
|---|
| 407 | 411 | goto out; |
|---|
| 408 | | - |
|---|
| 409 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 410 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 411 | | - vif->vifid, res_code); |
|---|
| 412 | | - ret = -EFAULT; |
|---|
| 413 | | - goto out; |
|---|
| 414 | | - } |
|---|
| 415 | 412 | |
|---|
| 416 | 413 | out: |
|---|
| 417 | 414 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 415 | + |
|---|
| 418 | 416 | return ret; |
|---|
| 419 | 417 | } |
|---|
| 420 | 418 | |
|---|
| 421 | | -int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, |
|---|
| 422 | | - u16 freq, const u8 *buf, size_t len) |
|---|
| 419 | +int qtnf_cmd_send_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, |
|---|
| 420 | + u16 freq, const u8 *buf, size_t len) |
|---|
| 423 | 421 | { |
|---|
| 424 | 422 | struct sk_buff *cmd_skb; |
|---|
| 425 | | - struct qlink_cmd_mgmt_frame_tx *cmd; |
|---|
| 426 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 423 | + struct qlink_cmd_frame_tx *cmd; |
|---|
| 427 | 424 | int ret; |
|---|
| 428 | 425 | |
|---|
| 429 | 426 | if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { |
|---|
| .. | .. |
|---|
| 433 | 430 | } |
|---|
| 434 | 431 | |
|---|
| 435 | 432 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| 436 | | - QLINK_CMD_SEND_MGMT_FRAME, |
|---|
| 433 | + QLINK_CMD_SEND_FRAME, |
|---|
| 437 | 434 | sizeof(*cmd)); |
|---|
| 438 | 435 | if (!cmd_skb) |
|---|
| 439 | 436 | return -ENOMEM; |
|---|
| 440 | 437 | |
|---|
| 441 | 438 | qtnf_bus_lock(vif->mac->bus); |
|---|
| 442 | 439 | |
|---|
| 443 | | - cmd = (struct qlink_cmd_mgmt_frame_tx *)cmd_skb->data; |
|---|
| 440 | + cmd = (struct qlink_cmd_frame_tx *)cmd_skb->data; |
|---|
| 444 | 441 | cmd->cookie = cpu_to_le32(cookie); |
|---|
| 445 | 442 | cmd->freq = cpu_to_le16(freq); |
|---|
| 446 | 443 | cmd->flags = cpu_to_le16(flags); |
|---|
| .. | .. |
|---|
| 448 | 445 | if (len && buf) |
|---|
| 449 | 446 | qtnf_cmd_skb_put_buffer(cmd_skb, buf, len); |
|---|
| 450 | 447 | |
|---|
| 451 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 452 | | - |
|---|
| 453 | | - if (unlikely(ret)) |
|---|
| 448 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 449 | + if (ret) |
|---|
| 454 | 450 | goto out; |
|---|
| 455 | | - |
|---|
| 456 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 457 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 458 | | - vif->vifid, res_code); |
|---|
| 459 | | - ret = -EFAULT; |
|---|
| 460 | | - goto out; |
|---|
| 461 | | - } |
|---|
| 462 | 451 | |
|---|
| 463 | 452 | out: |
|---|
| 464 | 453 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 454 | + |
|---|
| 465 | 455 | return ret; |
|---|
| 466 | 456 | } |
|---|
| 467 | 457 | |
|---|
| .. | .. |
|---|
| 469 | 459 | const u8 *buf, size_t len) |
|---|
| 470 | 460 | { |
|---|
| 471 | 461 | struct sk_buff *cmd_skb; |
|---|
| 472 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 473 | 462 | int ret; |
|---|
| 474 | 463 | |
|---|
| 475 | 464 | if (len > QTNF_MAX_CMD_BUF_SIZE) { |
|---|
| .. | .. |
|---|
| 487 | 476 | qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len); |
|---|
| 488 | 477 | |
|---|
| 489 | 478 | qtnf_bus_lock(vif->mac->bus); |
|---|
| 490 | | - |
|---|
| 491 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 492 | | - |
|---|
| 493 | | - if (unlikely(ret)) |
|---|
| 479 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 480 | + if (ret) |
|---|
| 494 | 481 | goto out; |
|---|
| 495 | | - |
|---|
| 496 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 497 | | - pr_err("VIF%u.%u frame %u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 498 | | - vif->vifid, frame_type, res_code); |
|---|
| 499 | | - ret = -EFAULT; |
|---|
| 500 | | - goto out; |
|---|
| 501 | | - } |
|---|
| 502 | 482 | |
|---|
| 503 | 483 | out: |
|---|
| 504 | 484 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 485 | + |
|---|
| 505 | 486 | return ret; |
|---|
| 506 | 487 | } |
|---|
| 507 | 488 | |
|---|
| .. | .. |
|---|
| 544 | 525 | rate_dst->flags |= RATE_INFO_FLAGS_MCS; |
|---|
| 545 | 526 | else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS) |
|---|
| 546 | 527 | rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS; |
|---|
| 528 | + else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_HE_MCS) |
|---|
| 529 | + rate_dst->flags |= RATE_INFO_FLAGS_HE_MCS; |
|---|
| 547 | 530 | |
|---|
| 548 | 531 | if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_SHORT_GI) |
|---|
| 549 | 532 | rate_dst->flags |= RATE_INFO_FLAGS_SHORT_GI; |
|---|
| .. | .. |
|---|
| 605 | 588 | } |
|---|
| 606 | 589 | |
|---|
| 607 | 590 | static void |
|---|
| 608 | | -qtnf_cmd_sta_info_parse(struct station_info *sinfo, |
|---|
| 609 | | - const struct qlink_tlv_hdr *tlv, |
|---|
| 591 | +qtnf_cmd_sta_info_parse(struct station_info *sinfo, const u8 *data, |
|---|
| 610 | 592 | size_t resp_size) |
|---|
| 611 | 593 | { |
|---|
| 594 | + const struct qlink_tlv_hdr *tlv; |
|---|
| 612 | 595 | const struct qlink_sta_stats *stats = NULL; |
|---|
| 613 | 596 | const u8 *map = NULL; |
|---|
| 614 | 597 | unsigned int map_len = 0; |
|---|
| .. | .. |
|---|
| 619 | 602 | (qtnf_utils_is_bit_set(map, bitn, map_len) && \ |
|---|
| 620 | 603 | (offsetofend(struct qlink_sta_stats, stat_name) <= stats_len)) |
|---|
| 621 | 604 | |
|---|
| 622 | | - while (resp_size >= sizeof(*tlv)) { |
|---|
| 605 | + qlink_for_each_tlv(tlv, data, resp_size) { |
|---|
| 623 | 606 | tlv_len = le16_to_cpu(tlv->len); |
|---|
| 624 | 607 | |
|---|
| 625 | 608 | switch (le16_to_cpu(tlv->type)) { |
|---|
| 626 | | - case QTN_TLV_ID_STA_STATS_MAP: |
|---|
| 609 | + case QTN_TLV_ID_BITMAP: |
|---|
| 627 | 610 | map_len = tlv_len; |
|---|
| 628 | 611 | map = tlv->val; |
|---|
| 629 | 612 | break; |
|---|
| .. | .. |
|---|
| 634 | 617 | default: |
|---|
| 635 | 618 | break; |
|---|
| 636 | 619 | } |
|---|
| 620 | + } |
|---|
| 637 | 621 | |
|---|
| 638 | | - resp_size -= tlv_len + sizeof(*tlv); |
|---|
| 639 | | - tlv = (const struct qlink_tlv_hdr *)(tlv->val + tlv_len); |
|---|
| 622 | + if (!qlink_tlv_parsing_ok(tlv, data, resp_size)) { |
|---|
| 623 | + pr_err("Malformed TLV buffer\n"); |
|---|
| 624 | + return; |
|---|
| 640 | 625 | } |
|---|
| 641 | 626 | |
|---|
| 642 | 627 | if (!map || !stats) |
|---|
| .. | .. |
|---|
| 732 | 717 | struct sk_buff *cmd_skb, *resp_skb = NULL; |
|---|
| 733 | 718 | struct qlink_cmd_get_sta_info *cmd; |
|---|
| 734 | 719 | const struct qlink_resp_get_sta_info *resp; |
|---|
| 735 | | - size_t var_resp_len; |
|---|
| 736 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 720 | + size_t var_resp_len = 0; |
|---|
| 737 | 721 | int ret = 0; |
|---|
| 738 | 722 | |
|---|
| 739 | 723 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 748 | 732 | ether_addr_copy(cmd->sta_addr, sta_mac); |
|---|
| 749 | 733 | |
|---|
| 750 | 734 | ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, |
|---|
| 751 | | - &res_code, sizeof(*resp), |
|---|
| 752 | | - &var_resp_len); |
|---|
| 753 | | - |
|---|
| 754 | | - if (unlikely(ret)) |
|---|
| 735 | + sizeof(*resp), &var_resp_len); |
|---|
| 736 | + if (ret) |
|---|
| 755 | 737 | goto out; |
|---|
| 756 | | - |
|---|
| 757 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 758 | | - switch (res_code) { |
|---|
| 759 | | - case QLINK_CMD_RESULT_ENOTFOUND: |
|---|
| 760 | | - pr_warn("VIF%u.%u: %pM STA not found\n", |
|---|
| 761 | | - vif->mac->macid, vif->vifid, sta_mac); |
|---|
| 762 | | - ret = -ENOENT; |
|---|
| 763 | | - break; |
|---|
| 764 | | - default: |
|---|
| 765 | | - pr_err("VIF%u.%u: can't get info for %pM: %u\n", |
|---|
| 766 | | - vif->mac->macid, vif->vifid, sta_mac, res_code); |
|---|
| 767 | | - ret = -EFAULT; |
|---|
| 768 | | - break; |
|---|
| 769 | | - } |
|---|
| 770 | | - goto out; |
|---|
| 771 | | - } |
|---|
| 772 | 738 | |
|---|
| 773 | 739 | resp = (const struct qlink_resp_get_sta_info *)resp_skb->data; |
|---|
| 774 | 740 | |
|---|
| 775 | | - if (unlikely(!ether_addr_equal(sta_mac, resp->sta_addr))) { |
|---|
| 741 | + if (!ether_addr_equal(sta_mac, resp->sta_addr)) { |
|---|
| 776 | 742 | pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n", |
|---|
| 777 | 743 | vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac); |
|---|
| 778 | 744 | ret = -EINVAL; |
|---|
| 779 | 745 | goto out; |
|---|
| 780 | 746 | } |
|---|
| 781 | 747 | |
|---|
| 782 | | - qtnf_cmd_sta_info_parse(sinfo, |
|---|
| 783 | | - (const struct qlink_tlv_hdr *)resp->info, |
|---|
| 784 | | - var_resp_len); |
|---|
| 748 | + qtnf_cmd_sta_info_parse(sinfo, resp->info, var_resp_len); |
|---|
| 785 | 749 | |
|---|
| 786 | 750 | out: |
|---|
| 787 | 751 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| .. | .. |
|---|
| 792 | 756 | |
|---|
| 793 | 757 | static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif, |
|---|
| 794 | 758 | enum nl80211_iftype iftype, |
|---|
| 759 | + int use4addr, |
|---|
| 795 | 760 | u8 *mac_addr, |
|---|
| 796 | 761 | enum qlink_cmd_type cmd_type) |
|---|
| 797 | 762 | { |
|---|
| 798 | 763 | struct sk_buff *cmd_skb, *resp_skb = NULL; |
|---|
| 799 | 764 | struct qlink_cmd_manage_intf *cmd; |
|---|
| 800 | 765 | const struct qlink_resp_manage_intf *resp; |
|---|
| 801 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 802 | 766 | int ret = 0; |
|---|
| 803 | 767 | |
|---|
| 804 | 768 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 810 | 774 | qtnf_bus_lock(vif->mac->bus); |
|---|
| 811 | 775 | |
|---|
| 812 | 776 | cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data; |
|---|
| 777 | + cmd->intf_info.use4addr = use4addr; |
|---|
| 813 | 778 | |
|---|
| 814 | 779 | switch (iftype) { |
|---|
| 815 | 780 | case NL80211_IFTYPE_AP: |
|---|
| .. | .. |
|---|
| 831 | 796 | eth_zero_addr(cmd->intf_info.mac_addr); |
|---|
| 832 | 797 | |
|---|
| 833 | 798 | ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, |
|---|
| 834 | | - &res_code, sizeof(*resp), NULL); |
|---|
| 835 | | - |
|---|
| 836 | | - if (unlikely(ret)) |
|---|
| 799 | + sizeof(*resp), NULL); |
|---|
| 800 | + if (ret) |
|---|
| 837 | 801 | goto out; |
|---|
| 838 | | - |
|---|
| 839 | | - ret = qtnf_cmd_resp_result_decode(res_code); |
|---|
| 840 | | - if (ret) { |
|---|
| 841 | | - pr_err("VIF%u.%u: CMD %d failed: %u\n", vif->mac->macid, |
|---|
| 842 | | - vif->vifid, cmd_type, res_code); |
|---|
| 843 | | - goto out; |
|---|
| 844 | | - } |
|---|
| 845 | 802 | |
|---|
| 846 | 803 | resp = (const struct qlink_resp_manage_intf *)resp_skb->data; |
|---|
| 847 | 804 | ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr); |
|---|
| .. | .. |
|---|
| 853 | 810 | return ret; |
|---|
| 854 | 811 | } |
|---|
| 855 | 812 | |
|---|
| 856 | | -int qtnf_cmd_send_add_intf(struct qtnf_vif *vif, |
|---|
| 857 | | - enum nl80211_iftype iftype, u8 *mac_addr) |
|---|
| 813 | +int qtnf_cmd_send_add_intf(struct qtnf_vif *vif, enum nl80211_iftype iftype, |
|---|
| 814 | + int use4addr, u8 *mac_addr) |
|---|
| 858 | 815 | { |
|---|
| 859 | | - return qtnf_cmd_send_add_change_intf(vif, iftype, mac_addr, |
|---|
| 816 | + return qtnf_cmd_send_add_change_intf(vif, iftype, use4addr, mac_addr, |
|---|
| 860 | 817 | QLINK_CMD_ADD_INTF); |
|---|
| 861 | 818 | } |
|---|
| 862 | 819 | |
|---|
| 863 | 820 | int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif, |
|---|
| 864 | | - enum nl80211_iftype iftype, u8 *mac_addr) |
|---|
| 821 | + enum nl80211_iftype iftype, |
|---|
| 822 | + int use4addr, |
|---|
| 823 | + u8 *mac_addr) |
|---|
| 865 | 824 | { |
|---|
| 866 | | - return qtnf_cmd_send_add_change_intf(vif, iftype, mac_addr, |
|---|
| 867 | | - QLINK_CMD_CHANGE_INTF); |
|---|
| 825 | + int ret; |
|---|
| 826 | + |
|---|
| 827 | + ret = qtnf_cmd_send_add_change_intf(vif, iftype, use4addr, mac_addr, |
|---|
| 828 | + QLINK_CMD_CHANGE_INTF); |
|---|
| 829 | + |
|---|
| 830 | + /* Regulatory settings may be different for different interface types */ |
|---|
| 831 | + if (ret == 0 && vif->wdev.iftype != iftype) { |
|---|
| 832 | + enum nl80211_band band; |
|---|
| 833 | + struct wiphy *wiphy = priv_to_wiphy(vif->mac); |
|---|
| 834 | + |
|---|
| 835 | + for (band = 0; band < NUM_NL80211_BANDS; ++band) { |
|---|
| 836 | + if (!wiphy->bands[band]) |
|---|
| 837 | + continue; |
|---|
| 838 | + |
|---|
| 839 | + qtnf_cmd_band_info_get(vif->mac, wiphy->bands[band]); |
|---|
| 840 | + } |
|---|
| 841 | + } |
|---|
| 842 | + |
|---|
| 843 | + return ret; |
|---|
| 868 | 844 | } |
|---|
| 869 | 845 | |
|---|
| 870 | 846 | int qtnf_cmd_send_del_intf(struct qtnf_vif *vif) |
|---|
| 871 | 847 | { |
|---|
| 872 | 848 | struct sk_buff *cmd_skb; |
|---|
| 873 | 849 | struct qlink_cmd_manage_intf *cmd; |
|---|
| 874 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 875 | 850 | int ret = 0; |
|---|
| 876 | 851 | |
|---|
| 877 | 852 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 901 | 876 | |
|---|
| 902 | 877 | eth_zero_addr(cmd->intf_info.mac_addr); |
|---|
| 903 | 878 | |
|---|
| 904 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 905 | | - |
|---|
| 906 | | - if (unlikely(ret)) |
|---|
| 879 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 880 | + if (ret) |
|---|
| 907 | 881 | goto out; |
|---|
| 908 | | - |
|---|
| 909 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 910 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 911 | | - vif->vifid, res_code); |
|---|
| 912 | | - ret = -EFAULT; |
|---|
| 913 | | - goto out; |
|---|
| 914 | | - } |
|---|
| 915 | 882 | |
|---|
| 916 | 883 | out: |
|---|
| 917 | 884 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 918 | 885 | return ret; |
|---|
| 919 | | -} |
|---|
| 920 | | - |
|---|
| 921 | | -static u32 qtnf_cmd_resp_reg_rule_flags_parse(u32 qflags) |
|---|
| 922 | | -{ |
|---|
| 923 | | - u32 flags = 0; |
|---|
| 924 | | - |
|---|
| 925 | | - if (qflags & QLINK_RRF_NO_OFDM) |
|---|
| 926 | | - flags |= NL80211_RRF_NO_OFDM; |
|---|
| 927 | | - |
|---|
| 928 | | - if (qflags & QLINK_RRF_NO_CCK) |
|---|
| 929 | | - flags |= NL80211_RRF_NO_CCK; |
|---|
| 930 | | - |
|---|
| 931 | | - if (qflags & QLINK_RRF_NO_INDOOR) |
|---|
| 932 | | - flags |= NL80211_RRF_NO_INDOOR; |
|---|
| 933 | | - |
|---|
| 934 | | - if (qflags & QLINK_RRF_NO_OUTDOOR) |
|---|
| 935 | | - flags |= NL80211_RRF_NO_OUTDOOR; |
|---|
| 936 | | - |
|---|
| 937 | | - if (qflags & QLINK_RRF_DFS) |
|---|
| 938 | | - flags |= NL80211_RRF_DFS; |
|---|
| 939 | | - |
|---|
| 940 | | - if (qflags & QLINK_RRF_PTP_ONLY) |
|---|
| 941 | | - flags |= NL80211_RRF_PTP_ONLY; |
|---|
| 942 | | - |
|---|
| 943 | | - if (qflags & QLINK_RRF_PTMP_ONLY) |
|---|
| 944 | | - flags |= NL80211_RRF_PTMP_ONLY; |
|---|
| 945 | | - |
|---|
| 946 | | - if (qflags & QLINK_RRF_NO_IR) |
|---|
| 947 | | - flags |= NL80211_RRF_NO_IR; |
|---|
| 948 | | - |
|---|
| 949 | | - if (qflags & QLINK_RRF_AUTO_BW) |
|---|
| 950 | | - flags |= NL80211_RRF_AUTO_BW; |
|---|
| 951 | | - |
|---|
| 952 | | - if (qflags & QLINK_RRF_IR_CONCURRENT) |
|---|
| 953 | | - flags |= NL80211_RRF_IR_CONCURRENT; |
|---|
| 954 | | - |
|---|
| 955 | | - if (qflags & QLINK_RRF_NO_HT40MINUS) |
|---|
| 956 | | - flags |= NL80211_RRF_NO_HT40MINUS; |
|---|
| 957 | | - |
|---|
| 958 | | - if (qflags & QLINK_RRF_NO_HT40PLUS) |
|---|
| 959 | | - flags |= NL80211_RRF_NO_HT40PLUS; |
|---|
| 960 | | - |
|---|
| 961 | | - if (qflags & QLINK_RRF_NO_80MHZ) |
|---|
| 962 | | - flags |= NL80211_RRF_NO_80MHZ; |
|---|
| 963 | | - |
|---|
| 964 | | - if (qflags & QLINK_RRF_NO_160MHZ) |
|---|
| 965 | | - flags |= NL80211_RRF_NO_160MHZ; |
|---|
| 966 | | - |
|---|
| 967 | | - return flags; |
|---|
| 968 | 886 | } |
|---|
| 969 | 887 | |
|---|
| 970 | 888 | static int |
|---|
| .. | .. |
|---|
| 974 | 892 | { |
|---|
| 975 | 893 | struct qtnf_hw_info *hwinfo = &bus->hw_info; |
|---|
| 976 | 894 | const struct qlink_tlv_hdr *tlv; |
|---|
| 977 | | - const struct qlink_tlv_reg_rule *tlv_rule; |
|---|
| 978 | 895 | const char *bld_name = NULL; |
|---|
| 979 | 896 | const char *bld_rev = NULL; |
|---|
| 980 | 897 | const char *bld_type = NULL; |
|---|
| .. | .. |
|---|
| 985 | 902 | const char *calibration_ver = NULL; |
|---|
| 986 | 903 | const char *uboot_ver = NULL; |
|---|
| 987 | 904 | u32 hw_ver = 0; |
|---|
| 988 | | - struct ieee80211_reg_rule *rule; |
|---|
| 989 | 905 | u16 tlv_type; |
|---|
| 990 | | - u16 tlv_value_len; |
|---|
| 991 | | - unsigned int rule_idx = 0; |
|---|
| 992 | | - |
|---|
| 993 | | - if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES)) |
|---|
| 994 | | - return -E2BIG; |
|---|
| 995 | | - |
|---|
| 996 | | - hwinfo->rd = kzalloc(sizeof(*hwinfo->rd) |
|---|
| 997 | | - + sizeof(struct ieee80211_reg_rule) |
|---|
| 998 | | - * resp->n_reg_rules, GFP_KERNEL); |
|---|
| 999 | | - |
|---|
| 1000 | | - if (!hwinfo->rd) |
|---|
| 1001 | | - return -ENOMEM; |
|---|
| 906 | + u16 tlv_len; |
|---|
| 1002 | 907 | |
|---|
| 1003 | 908 | hwinfo->num_mac = resp->num_mac; |
|---|
| 1004 | 909 | hwinfo->mac_bitmap = resp->mac_bitmap; |
|---|
| 1005 | 910 | hwinfo->fw_ver = le32_to_cpu(resp->fw_ver); |
|---|
| 1006 | | - hwinfo->ql_proto_ver = le16_to_cpu(resp->ql_proto_ver); |
|---|
| 1007 | 911 | hwinfo->total_tx_chain = resp->total_tx_chain; |
|---|
| 1008 | 912 | hwinfo->total_rx_chain = resp->total_rx_chain; |
|---|
| 1009 | | - hwinfo->hw_capab = le32_to_cpu(resp->hw_capab); |
|---|
| 1010 | | - hwinfo->rd->n_reg_rules = resp->n_reg_rules; |
|---|
| 1011 | | - hwinfo->rd->alpha2[0] = resp->alpha2[0]; |
|---|
| 1012 | | - hwinfo->rd->alpha2[1] = resp->alpha2[1]; |
|---|
| 1013 | 913 | |
|---|
| 1014 | 914 | bld_tmstamp = le32_to_cpu(resp->bld_tmstamp); |
|---|
| 1015 | 915 | plat_id = le32_to_cpu(resp->plat_id); |
|---|
| 1016 | 916 | hw_ver = le32_to_cpu(resp->hw_ver); |
|---|
| 1017 | 917 | |
|---|
| 1018 | | - switch (resp->dfs_region) { |
|---|
| 1019 | | - case QLINK_DFS_FCC: |
|---|
| 1020 | | - hwinfo->rd->dfs_region = NL80211_DFS_FCC; |
|---|
| 1021 | | - break; |
|---|
| 1022 | | - case QLINK_DFS_ETSI: |
|---|
| 1023 | | - hwinfo->rd->dfs_region = NL80211_DFS_ETSI; |
|---|
| 1024 | | - break; |
|---|
| 1025 | | - case QLINK_DFS_JP: |
|---|
| 1026 | | - hwinfo->rd->dfs_region = NL80211_DFS_JP; |
|---|
| 1027 | | - break; |
|---|
| 1028 | | - case QLINK_DFS_UNSET: |
|---|
| 1029 | | - default: |
|---|
| 1030 | | - hwinfo->rd->dfs_region = NL80211_DFS_UNSET; |
|---|
| 1031 | | - break; |
|---|
| 1032 | | - } |
|---|
| 1033 | | - |
|---|
| 1034 | | - tlv = (const struct qlink_tlv_hdr *)resp->info; |
|---|
| 1035 | | - |
|---|
| 1036 | | - while (info_len >= sizeof(*tlv)) { |
|---|
| 918 | + qlink_for_each_tlv(tlv, resp->info, info_len) { |
|---|
| 1037 | 919 | tlv_type = le16_to_cpu(tlv->type); |
|---|
| 1038 | | - tlv_value_len = le16_to_cpu(tlv->len); |
|---|
| 1039 | | - |
|---|
| 1040 | | - if (tlv_value_len + sizeof(*tlv) > info_len) { |
|---|
| 1041 | | - pr_warn("malformed TLV 0x%.2X; LEN: %u\n", |
|---|
| 1042 | | - tlv_type, tlv_value_len); |
|---|
| 1043 | | - return -EINVAL; |
|---|
| 1044 | | - } |
|---|
| 920 | + tlv_len = le16_to_cpu(tlv->len); |
|---|
| 1045 | 921 | |
|---|
| 1046 | 922 | switch (tlv_type) { |
|---|
| 1047 | | - case QTN_TLV_ID_REG_RULE: |
|---|
| 1048 | | - if (rule_idx >= resp->n_reg_rules) { |
|---|
| 1049 | | - pr_warn("unexpected number of rules: %u\n", |
|---|
| 1050 | | - resp->n_reg_rules); |
|---|
| 1051 | | - return -EINVAL; |
|---|
| 1052 | | - } |
|---|
| 1053 | | - |
|---|
| 1054 | | - if (tlv_value_len != sizeof(*tlv_rule) - sizeof(*tlv)) { |
|---|
| 1055 | | - pr_warn("malformed TLV 0x%.2X; LEN: %u\n", |
|---|
| 1056 | | - tlv_type, tlv_value_len); |
|---|
| 1057 | | - return -EINVAL; |
|---|
| 1058 | | - } |
|---|
| 1059 | | - |
|---|
| 1060 | | - tlv_rule = (const struct qlink_tlv_reg_rule *)tlv; |
|---|
| 1061 | | - rule = &hwinfo->rd->reg_rules[rule_idx++]; |
|---|
| 1062 | | - |
|---|
| 1063 | | - rule->freq_range.start_freq_khz = |
|---|
| 1064 | | - le32_to_cpu(tlv_rule->start_freq_khz); |
|---|
| 1065 | | - rule->freq_range.end_freq_khz = |
|---|
| 1066 | | - le32_to_cpu(tlv_rule->end_freq_khz); |
|---|
| 1067 | | - rule->freq_range.max_bandwidth_khz = |
|---|
| 1068 | | - le32_to_cpu(tlv_rule->max_bandwidth_khz); |
|---|
| 1069 | | - rule->power_rule.max_antenna_gain = |
|---|
| 1070 | | - le32_to_cpu(tlv_rule->max_antenna_gain); |
|---|
| 1071 | | - rule->power_rule.max_eirp = |
|---|
| 1072 | | - le32_to_cpu(tlv_rule->max_eirp); |
|---|
| 1073 | | - rule->dfs_cac_ms = |
|---|
| 1074 | | - le32_to_cpu(tlv_rule->dfs_cac_ms); |
|---|
| 1075 | | - rule->flags = qtnf_cmd_resp_reg_rule_flags_parse( |
|---|
| 1076 | | - le32_to_cpu(tlv_rule->flags)); |
|---|
| 1077 | | - break; |
|---|
| 1078 | 923 | case QTN_TLV_ID_BUILD_NAME: |
|---|
| 1079 | 924 | bld_name = (const void *)tlv->val; |
|---|
| 1080 | 925 | break; |
|---|
| .. | .. |
|---|
| 1096 | 941 | case QTN_TLV_ID_UBOOT_VER: |
|---|
| 1097 | 942 | uboot_ver = (const void *)tlv->val; |
|---|
| 1098 | 943 | break; |
|---|
| 1099 | | - case QTN_TLV_ID_MAX_SCAN_SSIDS: |
|---|
| 1100 | | - hwinfo->max_scan_ssids = *tlv->val; |
|---|
| 944 | + case QTN_TLV_ID_BITMAP: |
|---|
| 945 | + memcpy(hwinfo->hw_capab, tlv->val, |
|---|
| 946 | + min(sizeof(hwinfo->hw_capab), (size_t)tlv_len)); |
|---|
| 1101 | 947 | break; |
|---|
| 1102 | 948 | default: |
|---|
| 1103 | 949 | break; |
|---|
| 1104 | 950 | } |
|---|
| 1105 | | - |
|---|
| 1106 | | - info_len -= tlv_value_len + sizeof(*tlv); |
|---|
| 1107 | | - tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); |
|---|
| 1108 | 951 | } |
|---|
| 1109 | 952 | |
|---|
| 1110 | | - if (rule_idx != resp->n_reg_rules) { |
|---|
| 1111 | | - pr_warn("unexpected number of rules: expected %u got %u\n", |
|---|
| 1112 | | - resp->n_reg_rules, rule_idx); |
|---|
| 1113 | | - kfree(hwinfo->rd); |
|---|
| 1114 | | - hwinfo->rd = NULL; |
|---|
| 953 | + if (!qlink_tlv_parsing_ok(tlv, resp->info, info_len)) { |
|---|
| 954 | + pr_err("Malformed TLV buffer\n"); |
|---|
| 1115 | 955 | return -EINVAL; |
|---|
| 1116 | 956 | } |
|---|
| 1117 | 957 | |
|---|
| 1118 | | - pr_info("fw_version=%d, MACs map %#x, alpha2=\"%c%c\", chains Tx=%u Rx=%u, capab=0x%x\n", |
|---|
| 1119 | | - hwinfo->fw_ver, hwinfo->mac_bitmap, |
|---|
| 1120 | | - hwinfo->rd->alpha2[0], hwinfo->rd->alpha2[1], |
|---|
| 1121 | | - hwinfo->total_tx_chain, hwinfo->total_rx_chain, |
|---|
| 1122 | | - hwinfo->hw_capab); |
|---|
| 1123 | | - |
|---|
| 1124 | | - pr_info("\nBuild name: %s" \ |
|---|
| 1125 | | - "\nBuild revision: %s" \ |
|---|
| 1126 | | - "\nBuild type: %s" \ |
|---|
| 1127 | | - "\nBuild label: %s" \ |
|---|
| 1128 | | - "\nBuild timestamp: %lu" \ |
|---|
| 1129 | | - "\nPlatform ID: %lu" \ |
|---|
| 1130 | | - "\nHardware ID: %s" \ |
|---|
| 1131 | | - "\nCalibration version: %s" \ |
|---|
| 1132 | | - "\nU-Boot version: %s" \ |
|---|
| 1133 | | - "\nHardware version: 0x%08x", |
|---|
| 958 | + pr_info("\nBuild name: %s\n" |
|---|
| 959 | + "Build revision: %s\n" |
|---|
| 960 | + "Build type: %s\n" |
|---|
| 961 | + "Build label: %s\n" |
|---|
| 962 | + "Build timestamp: %lu\n" |
|---|
| 963 | + "Platform ID: %lu\n" |
|---|
| 964 | + "Hardware ID: %s\n" |
|---|
| 965 | + "Calibration version: %s\n" |
|---|
| 966 | + "U-Boot version: %s\n" |
|---|
| 967 | + "Hardware version: 0x%08x\n" |
|---|
| 968 | + "Qlink ver: %u.%u\n" |
|---|
| 969 | + "MACs map: %#x\n" |
|---|
| 970 | + "Chains Rx-Tx: %ux%u\n" |
|---|
| 971 | + "FW version: 0x%x\n", |
|---|
| 1134 | 972 | bld_name, bld_rev, bld_type, bld_label, |
|---|
| 1135 | 973 | (unsigned long)bld_tmstamp, |
|---|
| 1136 | 974 | (unsigned long)plat_id, |
|---|
| 1137 | | - hw_id, calibration_ver, uboot_ver, hw_ver); |
|---|
| 975 | + hw_id, calibration_ver, uboot_ver, hw_ver, |
|---|
| 976 | + QLINK_VER_MAJOR(bus->hw_info.ql_proto_ver), |
|---|
| 977 | + QLINK_VER_MINOR(bus->hw_info.ql_proto_ver), |
|---|
| 978 | + hwinfo->mac_bitmap, |
|---|
| 979 | + hwinfo->total_rx_chain, hwinfo->total_tx_chain, |
|---|
| 980 | + hwinfo->fw_ver); |
|---|
| 1138 | 981 | |
|---|
| 1139 | 982 | strlcpy(hwinfo->fw_version, bld_label, sizeof(hwinfo->fw_version)); |
|---|
| 1140 | 983 | hwinfo->hw_version = hw_ver; |
|---|
| .. | .. |
|---|
| 1173 | 1016 | } |
|---|
| 1174 | 1017 | } |
|---|
| 1175 | 1018 | |
|---|
| 1176 | | -static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, |
|---|
| 1177 | | - const u8 *tlv_buf, size_t tlv_buf_size) |
|---|
| 1019 | +static int |
|---|
| 1020 | +qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, |
|---|
| 1021 | + const struct qlink_resp_get_mac_info *resp, |
|---|
| 1022 | + size_t tlv_buf_size) |
|---|
| 1178 | 1023 | { |
|---|
| 1179 | | - struct ieee80211_iface_combination *comb = NULL; |
|---|
| 1024 | + struct ieee80211_iface_combination *comb = mac->macinfo.if_comb; |
|---|
| 1180 | 1025 | size_t n_comb = 0; |
|---|
| 1181 | 1026 | struct ieee80211_iface_limit *limits; |
|---|
| 1182 | | - const struct qlink_iface_comb_num *comb_num; |
|---|
| 1183 | 1027 | const struct qlink_iface_limit_record *rec; |
|---|
| 1184 | 1028 | const struct qlink_iface_limit *lim; |
|---|
| 1185 | 1029 | const struct qlink_wowlan_capab_data *wowlan; |
|---|
| 1186 | 1030 | u16 rec_len; |
|---|
| 1187 | 1031 | u16 tlv_type; |
|---|
| 1188 | 1032 | u16 tlv_value_len; |
|---|
| 1189 | | - size_t tlv_full_len; |
|---|
| 1190 | 1033 | const struct qlink_tlv_hdr *tlv; |
|---|
| 1191 | 1034 | u8 *ext_capa = NULL; |
|---|
| 1192 | 1035 | u8 *ext_capa_mask = NULL; |
|---|
| 1193 | 1036 | u8 ext_capa_len = 0; |
|---|
| 1194 | 1037 | u8 ext_capa_mask_len = 0; |
|---|
| 1195 | 1038 | int i = 0; |
|---|
| 1039 | + struct ieee80211_reg_rule *rule; |
|---|
| 1040 | + unsigned int rule_idx = 0; |
|---|
| 1041 | + const struct qlink_tlv_reg_rule *tlv_rule; |
|---|
| 1196 | 1042 | |
|---|
| 1197 | | - tlv = (const struct qlink_tlv_hdr *)tlv_buf; |
|---|
| 1198 | | - while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) { |
|---|
| 1043 | + if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES)) |
|---|
| 1044 | + return -E2BIG; |
|---|
| 1045 | + |
|---|
| 1046 | + mac->rd = kzalloc(struct_size(mac->rd, reg_rules, resp->n_reg_rules), |
|---|
| 1047 | + GFP_KERNEL); |
|---|
| 1048 | + if (!mac->rd) |
|---|
| 1049 | + return -ENOMEM; |
|---|
| 1050 | + |
|---|
| 1051 | + mac->rd->n_reg_rules = resp->n_reg_rules; |
|---|
| 1052 | + mac->rd->alpha2[0] = resp->alpha2[0]; |
|---|
| 1053 | + mac->rd->alpha2[1] = resp->alpha2[1]; |
|---|
| 1054 | + |
|---|
| 1055 | + switch (resp->dfs_region) { |
|---|
| 1056 | + case QLINK_DFS_FCC: |
|---|
| 1057 | + mac->rd->dfs_region = NL80211_DFS_FCC; |
|---|
| 1058 | + break; |
|---|
| 1059 | + case QLINK_DFS_ETSI: |
|---|
| 1060 | + mac->rd->dfs_region = NL80211_DFS_ETSI; |
|---|
| 1061 | + break; |
|---|
| 1062 | + case QLINK_DFS_JP: |
|---|
| 1063 | + mac->rd->dfs_region = NL80211_DFS_JP; |
|---|
| 1064 | + break; |
|---|
| 1065 | + case QLINK_DFS_UNSET: |
|---|
| 1066 | + default: |
|---|
| 1067 | + mac->rd->dfs_region = NL80211_DFS_UNSET; |
|---|
| 1068 | + break; |
|---|
| 1069 | + } |
|---|
| 1070 | + |
|---|
| 1071 | + qlink_for_each_tlv(tlv, resp->var_info, tlv_buf_size) { |
|---|
| 1199 | 1072 | tlv_type = le16_to_cpu(tlv->type); |
|---|
| 1200 | 1073 | tlv_value_len = le16_to_cpu(tlv->len); |
|---|
| 1201 | | - tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); |
|---|
| 1202 | | - if (tlv_full_len > tlv_buf_size) { |
|---|
| 1203 | | - pr_warn("MAC%u: malformed TLV 0x%.2X; LEN: %u\n", |
|---|
| 1204 | | - mac->macid, tlv_type, tlv_value_len); |
|---|
| 1205 | | - return -EINVAL; |
|---|
| 1206 | | - } |
|---|
| 1207 | 1074 | |
|---|
| 1208 | 1075 | switch (tlv_type) { |
|---|
| 1209 | | - case QTN_TLV_ID_NUM_IFACE_COMB: |
|---|
| 1210 | | - if (tlv_value_len != sizeof(*comb_num)) |
|---|
| 1211 | | - return -EINVAL; |
|---|
| 1212 | | - |
|---|
| 1213 | | - comb_num = (void *)tlv->val; |
|---|
| 1214 | | - |
|---|
| 1215 | | - /* free earlier iface comb memory */ |
|---|
| 1216 | | - qtnf_mac_iface_comb_free(mac); |
|---|
| 1217 | | - |
|---|
| 1218 | | - mac->macinfo.n_if_comb = |
|---|
| 1219 | | - le32_to_cpu(comb_num->iface_comb_num); |
|---|
| 1220 | | - |
|---|
| 1221 | | - mac->macinfo.if_comb = |
|---|
| 1222 | | - kcalloc(mac->macinfo.n_if_comb, |
|---|
| 1223 | | - sizeof(*mac->macinfo.if_comb), |
|---|
| 1224 | | - GFP_KERNEL); |
|---|
| 1225 | | - |
|---|
| 1226 | | - if (!mac->macinfo.if_comb) |
|---|
| 1227 | | - return -ENOMEM; |
|---|
| 1228 | | - |
|---|
| 1229 | | - comb = mac->macinfo.if_comb; |
|---|
| 1230 | | - |
|---|
| 1231 | | - pr_debug("MAC%u: %zu iface combinations\n", |
|---|
| 1232 | | - mac->macid, mac->macinfo.n_if_comb); |
|---|
| 1233 | | - |
|---|
| 1234 | | - break; |
|---|
| 1235 | 1076 | case QTN_TLV_ID_IFACE_LIMIT: |
|---|
| 1236 | 1077 | if (unlikely(!comb)) { |
|---|
| 1237 | 1078 | pr_warn("MAC%u: no combinations advertised\n", |
|---|
| .. | .. |
|---|
| 1313 | 1154 | mac->macinfo.wowlan = NULL; |
|---|
| 1314 | 1155 | qtnf_parse_wowlan_info(mac, wowlan); |
|---|
| 1315 | 1156 | break; |
|---|
| 1157 | + case QTN_TLV_ID_REG_RULE: |
|---|
| 1158 | + if (rule_idx >= resp->n_reg_rules) { |
|---|
| 1159 | + pr_warn("unexpected number of rules: %u\n", |
|---|
| 1160 | + resp->n_reg_rules); |
|---|
| 1161 | + return -EINVAL; |
|---|
| 1162 | + } |
|---|
| 1163 | + |
|---|
| 1164 | + if (tlv_value_len != sizeof(*tlv_rule) - sizeof(*tlv)) { |
|---|
| 1165 | + pr_warn("malformed TLV 0x%.2X; LEN: %u\n", |
|---|
| 1166 | + tlv_type, tlv_value_len); |
|---|
| 1167 | + return -EINVAL; |
|---|
| 1168 | + } |
|---|
| 1169 | + |
|---|
| 1170 | + tlv_rule = (const struct qlink_tlv_reg_rule *)tlv; |
|---|
| 1171 | + rule = &mac->rd->reg_rules[rule_idx++]; |
|---|
| 1172 | + qlink_utils_regrule_q2nl(rule, tlv_rule); |
|---|
| 1173 | + break; |
|---|
| 1316 | 1174 | default: |
|---|
| 1317 | 1175 | pr_warn("MAC%u: unknown TLV type %u\n", |
|---|
| 1318 | 1176 | mac->macid, tlv_type); |
|---|
| 1319 | 1177 | break; |
|---|
| 1320 | 1178 | } |
|---|
| 1321 | | - |
|---|
| 1322 | | - tlv_buf_size -= tlv_full_len; |
|---|
| 1323 | | - tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); |
|---|
| 1324 | 1179 | } |
|---|
| 1325 | 1180 | |
|---|
| 1326 | | - if (tlv_buf_size) { |
|---|
| 1327 | | - pr_warn("MAC%u: malformed TLV buf; bytes left: %zu\n", |
|---|
| 1328 | | - mac->macid, tlv_buf_size); |
|---|
| 1181 | + if (!qlink_tlv_parsing_ok(tlv, resp->var_info, tlv_buf_size)) { |
|---|
| 1182 | + pr_err("Malformed TLV buffer\n"); |
|---|
| 1329 | 1183 | return -EINVAL; |
|---|
| 1330 | 1184 | } |
|---|
| 1331 | 1185 | |
|---|
| .. | .. |
|---|
| 1338 | 1192 | if (ext_capa_len != ext_capa_mask_len) { |
|---|
| 1339 | 1193 | pr_err("MAC%u: ext_capa/_mask lengths mismatch: %u != %u\n", |
|---|
| 1340 | 1194 | mac->macid, ext_capa_len, ext_capa_mask_len); |
|---|
| 1195 | + return -EINVAL; |
|---|
| 1196 | + } |
|---|
| 1197 | + |
|---|
| 1198 | + if (rule_idx != resp->n_reg_rules) { |
|---|
| 1199 | + pr_warn("unexpected number of rules: expected %u got %u\n", |
|---|
| 1200 | + resp->n_reg_rules, rule_idx); |
|---|
| 1341 | 1201 | return -EINVAL; |
|---|
| 1342 | 1202 | } |
|---|
| 1343 | 1203 | |
|---|
| .. | .. |
|---|
| 1365 | 1225 | return 0; |
|---|
| 1366 | 1226 | } |
|---|
| 1367 | 1227 | |
|---|
| 1368 | | -static void |
|---|
| 1228 | +static int |
|---|
| 1369 | 1229 | qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac, |
|---|
| 1370 | 1230 | const struct qlink_resp_get_mac_info *resp_info) |
|---|
| 1371 | 1231 | { |
|---|
| 1372 | 1232 | struct qtnf_mac_info *mac_info; |
|---|
| 1373 | 1233 | struct qtnf_vif *vif; |
|---|
| 1374 | 1234 | |
|---|
| 1235 | + qtnf_mac_iface_comb_free(mac); |
|---|
| 1236 | + |
|---|
| 1375 | 1237 | mac_info = &mac->macinfo; |
|---|
| 1376 | 1238 | |
|---|
| 1377 | 1239 | mac_info->bands_cap = resp_info->bands_cap; |
|---|
| 1378 | | - memcpy(&mac_info->dev_mac, &resp_info->dev_mac, |
|---|
| 1379 | | - sizeof(mac_info->dev_mac)); |
|---|
| 1380 | | - |
|---|
| 1381 | | - ether_addr_copy(mac->macaddr, mac_info->dev_mac); |
|---|
| 1240 | + ether_addr_copy(mac->macaddr, resp_info->dev_mac); |
|---|
| 1382 | 1241 | |
|---|
| 1383 | 1242 | vif = qtnf_mac_get_base_vif(mac); |
|---|
| 1384 | 1243 | if (vif) |
|---|
| .. | .. |
|---|
| 1393 | 1252 | mac_info->radar_detect_widths = |
|---|
| 1394 | 1253 | qlink_chan_width_mask_to_nl(le16_to_cpu( |
|---|
| 1395 | 1254 | resp_info->radar_detect_widths)); |
|---|
| 1396 | | - mac_info->max_acl_mac_addrs = le32_to_cpu(resp_info->max_acl_mac_addrs); |
|---|
| 1255 | + mac_info->max_acl_mac_addrs = le16_to_cpu(resp_info->max_acl_mac_addrs); |
|---|
| 1256 | + mac_info->frag_thr = le32_to_cpu(resp_info->frag_threshold); |
|---|
| 1257 | + mac_info->rts_thr = le32_to_cpu(resp_info->rts_threshold); |
|---|
| 1258 | + mac_info->sretry_limit = resp_info->retry_short; |
|---|
| 1259 | + mac_info->lretry_limit = resp_info->retry_long; |
|---|
| 1260 | + mac_info->coverage_class = resp_info->coverage_class; |
|---|
| 1261 | + mac_info->max_scan_ssids = resp_info->max_scan_ssids; |
|---|
| 1397 | 1262 | |
|---|
| 1398 | 1263 | memcpy(&mac_info->ht_cap_mod_mask, &resp_info->ht_cap_mod_mask, |
|---|
| 1399 | 1264 | sizeof(mac_info->ht_cap_mod_mask)); |
|---|
| 1400 | 1265 | memcpy(&mac_info->vht_cap_mod_mask, &resp_info->vht_cap_mod_mask, |
|---|
| 1401 | 1266 | sizeof(mac_info->vht_cap_mod_mask)); |
|---|
| 1267 | + |
|---|
| 1268 | + mac_info->n_if_comb = resp_info->n_iface_combinations; |
|---|
| 1269 | + mac_info->if_comb = kcalloc(mac->macinfo.n_if_comb, |
|---|
| 1270 | + sizeof(*mac->macinfo.if_comb), |
|---|
| 1271 | + GFP_KERNEL); |
|---|
| 1272 | + |
|---|
| 1273 | + if (!mac->macinfo.if_comb) |
|---|
| 1274 | + return -ENOMEM; |
|---|
| 1275 | + |
|---|
| 1276 | + return 0; |
|---|
| 1402 | 1277 | } |
|---|
| 1403 | 1278 | |
|---|
| 1404 | 1279 | static void qtnf_cmd_resp_band_fill_htcap(const u8 *info, |
|---|
| .. | .. |
|---|
| 1428 | 1303 | memcpy(&bcap->vht_mcs, &vht_cap->supp_mcs, sizeof(bcap->vht_mcs)); |
|---|
| 1429 | 1304 | } |
|---|
| 1430 | 1305 | |
|---|
| 1306 | +static void qtnf_cmd_conv_iftype(struct ieee80211_sband_iftype_data |
|---|
| 1307 | + *iftype_data, |
|---|
| 1308 | + const struct qlink_sband_iftype_data |
|---|
| 1309 | + *qlink_data) |
|---|
| 1310 | +{ |
|---|
| 1311 | + iftype_data->types_mask = le16_to_cpu(qlink_data->types_mask); |
|---|
| 1312 | + |
|---|
| 1313 | + iftype_data->he_cap.has_he = true; |
|---|
| 1314 | + memcpy(&iftype_data->he_cap.he_cap_elem, &qlink_data->he_cap_elem, |
|---|
| 1315 | + sizeof(qlink_data->he_cap_elem)); |
|---|
| 1316 | + memcpy(iftype_data->he_cap.ppe_thres, qlink_data->ppe_thres, |
|---|
| 1317 | + ARRAY_SIZE(qlink_data->ppe_thres)); |
|---|
| 1318 | + |
|---|
| 1319 | + iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80 = |
|---|
| 1320 | + qlink_data->he_mcs_nss_supp.rx_mcs_80; |
|---|
| 1321 | + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80 = |
|---|
| 1322 | + qlink_data->he_mcs_nss_supp.tx_mcs_80; |
|---|
| 1323 | + iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_160 = |
|---|
| 1324 | + qlink_data->he_mcs_nss_supp.rx_mcs_160; |
|---|
| 1325 | + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160 = |
|---|
| 1326 | + qlink_data->he_mcs_nss_supp.tx_mcs_160; |
|---|
| 1327 | + iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80p80 = |
|---|
| 1328 | + qlink_data->he_mcs_nss_supp.rx_mcs_80p80; |
|---|
| 1329 | + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80p80 = |
|---|
| 1330 | + qlink_data->he_mcs_nss_supp.tx_mcs_80p80; |
|---|
| 1331 | +} |
|---|
| 1332 | + |
|---|
| 1333 | +static int qtnf_cmd_band_fill_iftype(const u8 *data, |
|---|
| 1334 | + struct ieee80211_supported_band *band) |
|---|
| 1335 | +{ |
|---|
| 1336 | + unsigned int i; |
|---|
| 1337 | + struct ieee80211_sband_iftype_data *iftype_data; |
|---|
| 1338 | + const struct qlink_tlv_iftype_data *tlv = |
|---|
| 1339 | + (const struct qlink_tlv_iftype_data *)data; |
|---|
| 1340 | + size_t payload_len = tlv->n_iftype_data * sizeof(*tlv->iftype_data) + |
|---|
| 1341 | + sizeof(*tlv) - |
|---|
| 1342 | + sizeof(struct qlink_tlv_hdr); |
|---|
| 1343 | + |
|---|
| 1344 | + if (tlv->hdr.len != cpu_to_le16(payload_len)) { |
|---|
| 1345 | + pr_err("bad IFTYPE_DATA TLV len %u\n", tlv->hdr.len); |
|---|
| 1346 | + return -EINVAL; |
|---|
| 1347 | + } |
|---|
| 1348 | + |
|---|
| 1349 | + kfree(band->iftype_data); |
|---|
| 1350 | + band->iftype_data = NULL; |
|---|
| 1351 | + band->n_iftype_data = tlv->n_iftype_data; |
|---|
| 1352 | + if (band->n_iftype_data == 0) |
|---|
| 1353 | + return 0; |
|---|
| 1354 | + |
|---|
| 1355 | + iftype_data = kcalloc(band->n_iftype_data, sizeof(*iftype_data), |
|---|
| 1356 | + GFP_KERNEL); |
|---|
| 1357 | + if (!iftype_data) { |
|---|
| 1358 | + band->n_iftype_data = 0; |
|---|
| 1359 | + return -ENOMEM; |
|---|
| 1360 | + } |
|---|
| 1361 | + band->iftype_data = iftype_data; |
|---|
| 1362 | + |
|---|
| 1363 | + for (i = 0; i < band->n_iftype_data; i++) |
|---|
| 1364 | + qtnf_cmd_conv_iftype(iftype_data++, &tlv->iftype_data[i]); |
|---|
| 1365 | + |
|---|
| 1366 | + return 0; |
|---|
| 1367 | +} |
|---|
| 1368 | + |
|---|
| 1431 | 1369 | static int |
|---|
| 1432 | 1370 | qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band, |
|---|
| 1433 | 1371 | struct qlink_resp_band_info_get *resp, |
|---|
| 1434 | 1372 | size_t payload_len) |
|---|
| 1435 | 1373 | { |
|---|
| 1436 | 1374 | u16 tlv_type; |
|---|
| 1437 | | - size_t tlv_len; |
|---|
| 1438 | 1375 | size_t tlv_dlen; |
|---|
| 1439 | 1376 | const struct qlink_tlv_hdr *tlv; |
|---|
| 1440 | 1377 | const struct qlink_channel *qchan; |
|---|
| 1441 | 1378 | struct ieee80211_channel *chan; |
|---|
| 1442 | 1379 | unsigned int chidx = 0; |
|---|
| 1443 | 1380 | u32 qflags; |
|---|
| 1381 | + int ret = -EINVAL; |
|---|
| 1444 | 1382 | |
|---|
| 1445 | 1383 | memset(&band->ht_cap, 0, sizeof(band->ht_cap)); |
|---|
| 1446 | 1384 | memset(&band->vht_cap, 0, sizeof(band->vht_cap)); |
|---|
| .. | .. |
|---|
| 1468 | 1406 | return -ENOMEM; |
|---|
| 1469 | 1407 | } |
|---|
| 1470 | 1408 | |
|---|
| 1471 | | - tlv = (struct qlink_tlv_hdr *)resp->info; |
|---|
| 1472 | | - |
|---|
| 1473 | | - while (payload_len >= sizeof(*tlv)) { |
|---|
| 1409 | + qlink_for_each_tlv(tlv, resp->info, payload_len) { |
|---|
| 1474 | 1410 | tlv_type = le16_to_cpu(tlv->type); |
|---|
| 1475 | 1411 | tlv_dlen = le16_to_cpu(tlv->len); |
|---|
| 1476 | | - tlv_len = tlv_dlen + sizeof(*tlv); |
|---|
| 1477 | | - |
|---|
| 1478 | | - if (tlv_len > payload_len) { |
|---|
| 1479 | | - pr_warn("malformed TLV 0x%.2X; LEN: %zu\n", |
|---|
| 1480 | | - tlv_type, tlv_len); |
|---|
| 1481 | | - goto error_ret; |
|---|
| 1482 | | - } |
|---|
| 1483 | 1412 | |
|---|
| 1484 | 1413 | switch (tlv_type) { |
|---|
| 1485 | 1414 | case QTN_TLV_ID_CHANNEL: |
|---|
| 1486 | 1415 | if (unlikely(tlv_dlen != sizeof(*qchan))) { |
|---|
| 1487 | 1416 | pr_err("invalid channel TLV len %zu\n", |
|---|
| 1488 | | - tlv_len); |
|---|
| 1417 | + tlv_dlen); |
|---|
| 1489 | 1418 | goto error_ret; |
|---|
| 1490 | 1419 | } |
|---|
| 1491 | 1420 | |
|---|
| .. | .. |
|---|
| 1578 | 1507 | qtnf_cmd_resp_band_fill_vhtcap(tlv->val, |
|---|
| 1579 | 1508 | &band->vht_cap); |
|---|
| 1580 | 1509 | break; |
|---|
| 1510 | + case QTN_TLV_ID_IFTYPE_DATA: |
|---|
| 1511 | + ret = qtnf_cmd_band_fill_iftype((const uint8_t *)tlv, |
|---|
| 1512 | + band); |
|---|
| 1513 | + if (ret) |
|---|
| 1514 | + goto error_ret; |
|---|
| 1515 | + break; |
|---|
| 1581 | 1516 | default: |
|---|
| 1582 | 1517 | pr_warn("unknown TLV type: %#x\n", tlv_type); |
|---|
| 1583 | 1518 | break; |
|---|
| 1584 | 1519 | } |
|---|
| 1585 | | - |
|---|
| 1586 | | - payload_len -= tlv_len; |
|---|
| 1587 | | - tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_dlen); |
|---|
| 1588 | 1520 | } |
|---|
| 1589 | 1521 | |
|---|
| 1590 | | - if (payload_len) { |
|---|
| 1591 | | - pr_err("malformed TLV buf; bytes left: %zu\n", payload_len); |
|---|
| 1522 | + if (!qlink_tlv_parsing_ok(tlv, resp->info, payload_len)) { |
|---|
| 1523 | + pr_err("Malformed TLV buffer\n"); |
|---|
| 1592 | 1524 | goto error_ret; |
|---|
| 1593 | 1525 | } |
|---|
| 1594 | 1526 | |
|---|
| .. | .. |
|---|
| 1605 | 1537 | band->channels = NULL; |
|---|
| 1606 | 1538 | band->n_channels = 0; |
|---|
| 1607 | 1539 | |
|---|
| 1608 | | - return -EINVAL; |
|---|
| 1609 | | -} |
|---|
| 1610 | | - |
|---|
| 1611 | | -static int qtnf_cmd_resp_proc_phy_params(struct qtnf_wmac *mac, |
|---|
| 1612 | | - const u8 *payload, size_t payload_len) |
|---|
| 1613 | | -{ |
|---|
| 1614 | | - struct qtnf_mac_info *mac_info; |
|---|
| 1615 | | - struct qlink_tlv_frag_rts_thr *phy_thr; |
|---|
| 1616 | | - struct qlink_tlv_rlimit *limit; |
|---|
| 1617 | | - struct qlink_tlv_cclass *class; |
|---|
| 1618 | | - u16 tlv_type; |
|---|
| 1619 | | - u16 tlv_value_len; |
|---|
| 1620 | | - size_t tlv_full_len; |
|---|
| 1621 | | - const struct qlink_tlv_hdr *tlv; |
|---|
| 1622 | | - |
|---|
| 1623 | | - mac_info = &mac->macinfo; |
|---|
| 1624 | | - |
|---|
| 1625 | | - tlv = (struct qlink_tlv_hdr *)payload; |
|---|
| 1626 | | - while (payload_len >= sizeof(struct qlink_tlv_hdr)) { |
|---|
| 1627 | | - tlv_type = le16_to_cpu(tlv->type); |
|---|
| 1628 | | - tlv_value_len = le16_to_cpu(tlv->len); |
|---|
| 1629 | | - tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); |
|---|
| 1630 | | - |
|---|
| 1631 | | - if (tlv_full_len > payload_len) { |
|---|
| 1632 | | - pr_warn("MAC%u: malformed TLV 0x%.2X; LEN: %u\n", |
|---|
| 1633 | | - mac->macid, tlv_type, tlv_value_len); |
|---|
| 1634 | | - return -EINVAL; |
|---|
| 1635 | | - } |
|---|
| 1636 | | - |
|---|
| 1637 | | - switch (tlv_type) { |
|---|
| 1638 | | - case QTN_TLV_ID_FRAG_THRESH: |
|---|
| 1639 | | - phy_thr = (void *)tlv; |
|---|
| 1640 | | - mac_info->frag_thr = (u32)le16_to_cpu(phy_thr->thr); |
|---|
| 1641 | | - break; |
|---|
| 1642 | | - case QTN_TLV_ID_RTS_THRESH: |
|---|
| 1643 | | - phy_thr = (void *)tlv; |
|---|
| 1644 | | - mac_info->rts_thr = (u32)le16_to_cpu(phy_thr->thr); |
|---|
| 1645 | | - break; |
|---|
| 1646 | | - case QTN_TLV_ID_SRETRY_LIMIT: |
|---|
| 1647 | | - limit = (void *)tlv; |
|---|
| 1648 | | - mac_info->sretry_limit = limit->rlimit; |
|---|
| 1649 | | - break; |
|---|
| 1650 | | - case QTN_TLV_ID_LRETRY_LIMIT: |
|---|
| 1651 | | - limit = (void *)tlv; |
|---|
| 1652 | | - mac_info->lretry_limit = limit->rlimit; |
|---|
| 1653 | | - break; |
|---|
| 1654 | | - case QTN_TLV_ID_COVERAGE_CLASS: |
|---|
| 1655 | | - class = (void *)tlv; |
|---|
| 1656 | | - mac_info->coverage_class = class->cclass; |
|---|
| 1657 | | - break; |
|---|
| 1658 | | - default: |
|---|
| 1659 | | - pr_err("MAC%u: Unknown TLV type: %#x\n", mac->macid, |
|---|
| 1660 | | - le16_to_cpu(tlv->type)); |
|---|
| 1661 | | - break; |
|---|
| 1662 | | - } |
|---|
| 1663 | | - |
|---|
| 1664 | | - payload_len -= tlv_full_len; |
|---|
| 1665 | | - tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); |
|---|
| 1666 | | - } |
|---|
| 1667 | | - |
|---|
| 1668 | | - if (payload_len) { |
|---|
| 1669 | | - pr_warn("MAC%u: malformed TLV buf; bytes left: %zu\n", |
|---|
| 1670 | | - mac->macid, payload_len); |
|---|
| 1671 | | - return -EINVAL; |
|---|
| 1672 | | - } |
|---|
| 1673 | | - |
|---|
| 1674 | | - return 0; |
|---|
| 1675 | | -} |
|---|
| 1676 | | - |
|---|
| 1677 | | -static int |
|---|
| 1678 | | -qtnf_cmd_resp_proc_chan_stat_info(struct qtnf_chan_stats *stats, |
|---|
| 1679 | | - const u8 *payload, size_t payload_len) |
|---|
| 1680 | | -{ |
|---|
| 1681 | | - struct qlink_chan_stats *qlink_stats; |
|---|
| 1682 | | - const struct qlink_tlv_hdr *tlv; |
|---|
| 1683 | | - size_t tlv_full_len; |
|---|
| 1684 | | - u16 tlv_value_len; |
|---|
| 1685 | | - u16 tlv_type; |
|---|
| 1686 | | - |
|---|
| 1687 | | - tlv = (struct qlink_tlv_hdr *)payload; |
|---|
| 1688 | | - while (payload_len >= sizeof(struct qlink_tlv_hdr)) { |
|---|
| 1689 | | - tlv_type = le16_to_cpu(tlv->type); |
|---|
| 1690 | | - tlv_value_len = le16_to_cpu(tlv->len); |
|---|
| 1691 | | - tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); |
|---|
| 1692 | | - if (tlv_full_len > payload_len) { |
|---|
| 1693 | | - pr_warn("malformed TLV 0x%.2X; LEN: %u\n", |
|---|
| 1694 | | - tlv_type, tlv_value_len); |
|---|
| 1695 | | - return -EINVAL; |
|---|
| 1696 | | - } |
|---|
| 1697 | | - switch (tlv_type) { |
|---|
| 1698 | | - case QTN_TLV_ID_CHANNEL_STATS: |
|---|
| 1699 | | - if (unlikely(tlv_value_len != sizeof(*qlink_stats))) { |
|---|
| 1700 | | - pr_err("invalid CHANNEL_STATS entry size\n"); |
|---|
| 1701 | | - return -EINVAL; |
|---|
| 1702 | | - } |
|---|
| 1703 | | - |
|---|
| 1704 | | - qlink_stats = (void *)tlv->val; |
|---|
| 1705 | | - |
|---|
| 1706 | | - stats->chan_num = le32_to_cpu(qlink_stats->chan_num); |
|---|
| 1707 | | - stats->cca_tx = le32_to_cpu(qlink_stats->cca_tx); |
|---|
| 1708 | | - stats->cca_rx = le32_to_cpu(qlink_stats->cca_rx); |
|---|
| 1709 | | - stats->cca_busy = le32_to_cpu(qlink_stats->cca_busy); |
|---|
| 1710 | | - stats->cca_try = le32_to_cpu(qlink_stats->cca_try); |
|---|
| 1711 | | - stats->chan_noise = qlink_stats->chan_noise; |
|---|
| 1712 | | - |
|---|
| 1713 | | - pr_debug("chan(%u) try(%u) busy(%u) noise(%d)\n", |
|---|
| 1714 | | - stats->chan_num, stats->cca_try, |
|---|
| 1715 | | - stats->cca_busy, stats->chan_noise); |
|---|
| 1716 | | - break; |
|---|
| 1717 | | - default: |
|---|
| 1718 | | - pr_warn("Unknown TLV type: %#x\n", |
|---|
| 1719 | | - le16_to_cpu(tlv->type)); |
|---|
| 1720 | | - } |
|---|
| 1721 | | - payload_len -= tlv_full_len; |
|---|
| 1722 | | - tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); |
|---|
| 1723 | | - } |
|---|
| 1724 | | - |
|---|
| 1725 | | - if (payload_len) { |
|---|
| 1726 | | - pr_warn("malformed TLV buf; bytes left: %zu\n", payload_len); |
|---|
| 1727 | | - return -EINVAL; |
|---|
| 1728 | | - } |
|---|
| 1729 | | - |
|---|
| 1730 | | - return 0; |
|---|
| 1540 | + return ret; |
|---|
| 1731 | 1541 | } |
|---|
| 1732 | 1542 | |
|---|
| 1733 | 1543 | int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac) |
|---|
| 1734 | 1544 | { |
|---|
| 1735 | 1545 | struct sk_buff *cmd_skb, *resp_skb = NULL; |
|---|
| 1736 | 1546 | const struct qlink_resp_get_mac_info *resp; |
|---|
| 1737 | | - size_t var_data_len; |
|---|
| 1738 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 1547 | + size_t var_data_len = 0; |
|---|
| 1739 | 1548 | int ret = 0; |
|---|
| 1740 | 1549 | |
|---|
| 1741 | 1550 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, |
|---|
| .. | .. |
|---|
| 1745 | 1554 | return -ENOMEM; |
|---|
| 1746 | 1555 | |
|---|
| 1747 | 1556 | qtnf_bus_lock(mac->bus); |
|---|
| 1748 | | - |
|---|
| 1749 | | - ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, |
|---|
| 1557 | + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, |
|---|
| 1750 | 1558 | sizeof(*resp), &var_data_len); |
|---|
| 1751 | | - if (unlikely(ret)) |
|---|
| 1559 | + if (ret) |
|---|
| 1752 | 1560 | goto out; |
|---|
| 1753 | | - |
|---|
| 1754 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 1755 | | - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); |
|---|
| 1756 | | - ret = -EFAULT; |
|---|
| 1757 | | - goto out; |
|---|
| 1758 | | - } |
|---|
| 1759 | 1561 | |
|---|
| 1760 | 1562 | resp = (const struct qlink_resp_get_mac_info *)resp_skb->data; |
|---|
| 1761 | | - qtnf_cmd_resp_proc_mac_info(mac, resp); |
|---|
| 1762 | | - ret = qtnf_parse_variable_mac_info(mac, resp->var_info, var_data_len); |
|---|
| 1563 | + ret = qtnf_cmd_resp_proc_mac_info(mac, resp); |
|---|
| 1564 | + if (ret) |
|---|
| 1565 | + goto out; |
|---|
| 1566 | + |
|---|
| 1567 | + ret = qtnf_parse_variable_mac_info(mac, resp, var_data_len); |
|---|
| 1763 | 1568 | |
|---|
| 1764 | 1569 | out: |
|---|
| 1765 | 1570 | qtnf_bus_unlock(mac->bus); |
|---|
| .. | .. |
|---|
| 1772 | 1577 | { |
|---|
| 1773 | 1578 | struct sk_buff *cmd_skb, *resp_skb = NULL; |
|---|
| 1774 | 1579 | const struct qlink_resp_get_hw_info *resp; |
|---|
| 1775 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 1580 | + size_t info_len = 0; |
|---|
| 1776 | 1581 | int ret = 0; |
|---|
| 1777 | | - size_t info_len; |
|---|
| 1778 | 1582 | |
|---|
| 1779 | 1583 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, |
|---|
| 1780 | 1584 | QLINK_CMD_GET_HW_INFO, |
|---|
| .. | .. |
|---|
| 1783 | 1587 | return -ENOMEM; |
|---|
| 1784 | 1588 | |
|---|
| 1785 | 1589 | qtnf_bus_lock(bus); |
|---|
| 1786 | | - |
|---|
| 1787 | | - ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, |
|---|
| 1590 | + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, |
|---|
| 1788 | 1591 | sizeof(*resp), &info_len); |
|---|
| 1789 | | - |
|---|
| 1790 | | - if (unlikely(ret)) |
|---|
| 1592 | + if (ret) |
|---|
| 1791 | 1593 | goto out; |
|---|
| 1792 | | - |
|---|
| 1793 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 1794 | | - pr_err("cmd exec failed: 0x%.4X\n", res_code); |
|---|
| 1795 | | - ret = -EFAULT; |
|---|
| 1796 | | - goto out; |
|---|
| 1797 | | - } |
|---|
| 1798 | 1594 | |
|---|
| 1799 | 1595 | resp = (const struct qlink_resp_get_hw_info *)resp_skb->data; |
|---|
| 1800 | 1596 | ret = qtnf_cmd_resp_proc_hw_info(bus, resp, info_len); |
|---|
| .. | .. |
|---|
| 1810 | 1606 | struct ieee80211_supported_band *band) |
|---|
| 1811 | 1607 | { |
|---|
| 1812 | 1608 | struct sk_buff *cmd_skb, *resp_skb = NULL; |
|---|
| 1813 | | - size_t info_len; |
|---|
| 1814 | 1609 | struct qlink_cmd_band_info_get *cmd; |
|---|
| 1815 | 1610 | struct qlink_resp_band_info_get *resp; |
|---|
| 1816 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 1611 | + size_t info_len = 0; |
|---|
| 1817 | 1612 | int ret = 0; |
|---|
| 1818 | | - u8 qband; |
|---|
| 1819 | | - |
|---|
| 1820 | | - switch (band->band) { |
|---|
| 1821 | | - case NL80211_BAND_2GHZ: |
|---|
| 1822 | | - qband = QLINK_BAND_2GHZ; |
|---|
| 1823 | | - break; |
|---|
| 1824 | | - case NL80211_BAND_5GHZ: |
|---|
| 1825 | | - qband = QLINK_BAND_5GHZ; |
|---|
| 1826 | | - break; |
|---|
| 1827 | | - case NL80211_BAND_60GHZ: |
|---|
| 1828 | | - qband = QLINK_BAND_60GHZ; |
|---|
| 1829 | | - break; |
|---|
| 1830 | | - default: |
|---|
| 1831 | | - return -EINVAL; |
|---|
| 1832 | | - } |
|---|
| 1613 | + u8 qband = qlink_utils_band_cfg2q(band->band); |
|---|
| 1833 | 1614 | |
|---|
| 1834 | 1615 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, |
|---|
| 1835 | 1616 | QLINK_CMD_BAND_INFO_GET, |
|---|
| .. | .. |
|---|
| 1841 | 1622 | cmd->band = qband; |
|---|
| 1842 | 1623 | |
|---|
| 1843 | 1624 | qtnf_bus_lock(mac->bus); |
|---|
| 1844 | | - |
|---|
| 1845 | | - ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, |
|---|
| 1625 | + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, |
|---|
| 1846 | 1626 | sizeof(*resp), &info_len); |
|---|
| 1847 | | - |
|---|
| 1848 | | - if (unlikely(ret)) |
|---|
| 1627 | + if (ret) |
|---|
| 1849 | 1628 | goto out; |
|---|
| 1850 | | - |
|---|
| 1851 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 1852 | | - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); |
|---|
| 1853 | | - ret = -EFAULT; |
|---|
| 1854 | | - goto out; |
|---|
| 1855 | | - } |
|---|
| 1856 | 1629 | |
|---|
| 1857 | 1630 | resp = (struct qlink_resp_band_info_get *)resp_skb->data; |
|---|
| 1858 | 1631 | if (resp->band != qband) { |
|---|
| .. | .. |
|---|
| 1871 | 1644 | return ret; |
|---|
| 1872 | 1645 | } |
|---|
| 1873 | 1646 | |
|---|
| 1874 | | -int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac) |
|---|
| 1875 | | -{ |
|---|
| 1876 | | - struct sk_buff *cmd_skb, *resp_skb = NULL; |
|---|
| 1877 | | - size_t response_size; |
|---|
| 1878 | | - struct qlink_resp_phy_params *resp; |
|---|
| 1879 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 1880 | | - int ret = 0; |
|---|
| 1881 | | - |
|---|
| 1882 | | - cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, |
|---|
| 1883 | | - QLINK_CMD_PHY_PARAMS_GET, |
|---|
| 1884 | | - sizeof(struct qlink_cmd)); |
|---|
| 1885 | | - if (!cmd_skb) |
|---|
| 1886 | | - return -ENOMEM; |
|---|
| 1887 | | - |
|---|
| 1888 | | - qtnf_bus_lock(mac->bus); |
|---|
| 1889 | | - |
|---|
| 1890 | | - ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, |
|---|
| 1891 | | - sizeof(*resp), &response_size); |
|---|
| 1892 | | - |
|---|
| 1893 | | - if (unlikely(ret)) |
|---|
| 1894 | | - goto out; |
|---|
| 1895 | | - |
|---|
| 1896 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 1897 | | - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); |
|---|
| 1898 | | - ret = -EFAULT; |
|---|
| 1899 | | - goto out; |
|---|
| 1900 | | - } |
|---|
| 1901 | | - |
|---|
| 1902 | | - resp = (struct qlink_resp_phy_params *)resp_skb->data; |
|---|
| 1903 | | - ret = qtnf_cmd_resp_proc_phy_params(mac, resp->info, response_size); |
|---|
| 1904 | | - |
|---|
| 1905 | | -out: |
|---|
| 1906 | | - qtnf_bus_unlock(mac->bus); |
|---|
| 1907 | | - consume_skb(resp_skb); |
|---|
| 1908 | | - |
|---|
| 1909 | | - return ret; |
|---|
| 1910 | | -} |
|---|
| 1911 | | - |
|---|
| 1912 | 1647 | int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed) |
|---|
| 1913 | 1648 | { |
|---|
| 1914 | 1649 | struct wiphy *wiphy = priv_to_wiphy(mac); |
|---|
| 1915 | 1650 | struct sk_buff *cmd_skb; |
|---|
| 1916 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 1917 | 1651 | int ret = 0; |
|---|
| 1918 | 1652 | |
|---|
| 1919 | 1653 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, |
|---|
| .. | .. |
|---|
| 1925 | 1659 | qtnf_bus_lock(mac->bus); |
|---|
| 1926 | 1660 | |
|---|
| 1927 | 1661 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) |
|---|
| 1928 | | - qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_FRAG_THRESH, |
|---|
| 1662 | + qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_FRAG_THRESH, |
|---|
| 1929 | 1663 | wiphy->frag_threshold); |
|---|
| 1930 | 1664 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) |
|---|
| 1931 | | - qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_RTS_THRESH, |
|---|
| 1665 | + qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_RTS_THRESH, |
|---|
| 1932 | 1666 | wiphy->rts_threshold); |
|---|
| 1933 | 1667 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) |
|---|
| 1934 | | - qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS, |
|---|
| 1935 | | - wiphy->coverage_class); |
|---|
| 1668 | + qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS, |
|---|
| 1669 | + wiphy->coverage_class); |
|---|
| 1936 | 1670 | |
|---|
| 1937 | | - ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); |
|---|
| 1671 | + if (changed & WIPHY_PARAM_RETRY_LONG) |
|---|
| 1672 | + qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_LRETRY_LIMIT, |
|---|
| 1673 | + wiphy->retry_long); |
|---|
| 1938 | 1674 | |
|---|
| 1939 | | - if (unlikely(ret)) |
|---|
| 1675 | + if (changed & WIPHY_PARAM_RETRY_SHORT) |
|---|
| 1676 | + qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_SRETRY_LIMIT, |
|---|
| 1677 | + wiphy->retry_short); |
|---|
| 1678 | + |
|---|
| 1679 | + ret = qtnf_cmd_send(mac->bus, cmd_skb); |
|---|
| 1680 | + if (ret) |
|---|
| 1940 | 1681 | goto out; |
|---|
| 1941 | | - |
|---|
| 1942 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 1943 | | - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); |
|---|
| 1944 | | - ret = -EFAULT; |
|---|
| 1945 | | - goto out; |
|---|
| 1946 | | - } |
|---|
| 1947 | 1682 | |
|---|
| 1948 | 1683 | out: |
|---|
| 1949 | 1684 | qtnf_bus_unlock(mac->bus); |
|---|
| 1685 | + |
|---|
| 1950 | 1686 | return ret; |
|---|
| 1951 | 1687 | } |
|---|
| 1952 | 1688 | |
|---|
| 1953 | 1689 | int qtnf_cmd_send_init_fw(struct qtnf_bus *bus) |
|---|
| 1954 | 1690 | { |
|---|
| 1691 | + struct sk_buff *resp_skb = NULL; |
|---|
| 1692 | + struct qlink_resp_init_fw *resp; |
|---|
| 1693 | + struct qlink_cmd_init_fw *cmd; |
|---|
| 1955 | 1694 | struct sk_buff *cmd_skb; |
|---|
| 1956 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 1957 | | - int ret = 0; |
|---|
| 1695 | + size_t info_len = 0; |
|---|
| 1696 | + int ret; |
|---|
| 1958 | 1697 | |
|---|
| 1959 | 1698 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, |
|---|
| 1960 | 1699 | QLINK_CMD_FW_INIT, |
|---|
| 1961 | | - sizeof(struct qlink_cmd)); |
|---|
| 1700 | + sizeof(*cmd)); |
|---|
| 1962 | 1701 | if (!cmd_skb) |
|---|
| 1963 | 1702 | return -ENOMEM; |
|---|
| 1964 | 1703 | |
|---|
| 1704 | + cmd = (struct qlink_cmd_init_fw *)cmd_skb->data; |
|---|
| 1705 | + cmd->qlink_proto_ver = cpu_to_le32(QLINK_PROTO_VER); |
|---|
| 1706 | + |
|---|
| 1965 | 1707 | qtnf_bus_lock(bus); |
|---|
| 1708 | + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, |
|---|
| 1709 | + sizeof(*resp), &info_len); |
|---|
| 1710 | + qtnf_bus_unlock(bus); |
|---|
| 1966 | 1711 | |
|---|
| 1967 | | - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); |
|---|
| 1968 | | - |
|---|
| 1969 | | - if (unlikely(ret)) |
|---|
| 1712 | + if (ret) |
|---|
| 1970 | 1713 | goto out; |
|---|
| 1971 | 1714 | |
|---|
| 1972 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 1973 | | - pr_err("cmd exec failed: 0x%.4X\n", res_code); |
|---|
| 1974 | | - ret = -EFAULT; |
|---|
| 1975 | | - goto out; |
|---|
| 1976 | | - } |
|---|
| 1715 | + resp = (struct qlink_resp_init_fw *)resp_skb->data; |
|---|
| 1716 | + bus->hw_info.ql_proto_ver = le32_to_cpu(resp->qlink_proto_ver); |
|---|
| 1977 | 1717 | |
|---|
| 1978 | 1718 | out: |
|---|
| 1979 | | - qtnf_bus_unlock(bus); |
|---|
| 1719 | + consume_skb(resp_skb); |
|---|
| 1980 | 1720 | return ret; |
|---|
| 1981 | 1721 | } |
|---|
| 1982 | 1722 | |
|---|
| .. | .. |
|---|
| 1991 | 1731 | return; |
|---|
| 1992 | 1732 | |
|---|
| 1993 | 1733 | qtnf_bus_lock(bus); |
|---|
| 1994 | | - |
|---|
| 1995 | | - qtnf_cmd_send(bus, cmd_skb, NULL); |
|---|
| 1996 | | - |
|---|
| 1734 | + qtnf_cmd_send(bus, cmd_skb); |
|---|
| 1997 | 1735 | qtnf_bus_unlock(bus); |
|---|
| 1998 | 1736 | } |
|---|
| 1999 | 1737 | |
|---|
| .. | .. |
|---|
| 2002 | 1740 | { |
|---|
| 2003 | 1741 | struct sk_buff *cmd_skb; |
|---|
| 2004 | 1742 | struct qlink_cmd_add_key *cmd; |
|---|
| 2005 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2006 | 1743 | int ret = 0; |
|---|
| 2007 | 1744 | |
|---|
| 2008 | 1745 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2034 | 1771 | params->seq, |
|---|
| 2035 | 1772 | params->seq_len); |
|---|
| 2036 | 1773 | |
|---|
| 2037 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2038 | | - if (unlikely(ret)) |
|---|
| 1774 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 1775 | + if (ret) |
|---|
| 2039 | 1776 | goto out; |
|---|
| 2040 | | - |
|---|
| 2041 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2042 | | - pr_err("VIF%u.%u: CMD failed: %u\n", |
|---|
| 2043 | | - vif->mac->macid, vif->vifid, res_code); |
|---|
| 2044 | | - ret = -EFAULT; |
|---|
| 2045 | | - goto out; |
|---|
| 2046 | | - } |
|---|
| 2047 | 1777 | |
|---|
| 2048 | 1778 | out: |
|---|
| 2049 | 1779 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 1780 | + |
|---|
| 2050 | 1781 | return ret; |
|---|
| 2051 | 1782 | } |
|---|
| 2052 | 1783 | |
|---|
| .. | .. |
|---|
| 2055 | 1786 | { |
|---|
| 2056 | 1787 | struct sk_buff *cmd_skb; |
|---|
| 2057 | 1788 | struct qlink_cmd_del_key *cmd; |
|---|
| 2058 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2059 | 1789 | int ret = 0; |
|---|
| 2060 | 1790 | |
|---|
| 2061 | 1791 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2075 | 1805 | |
|---|
| 2076 | 1806 | cmd->key_index = key_index; |
|---|
| 2077 | 1807 | cmd->pairwise = pairwise; |
|---|
| 2078 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2079 | | - if (unlikely(ret)) |
|---|
| 2080 | | - goto out; |
|---|
| 2081 | 1808 | |
|---|
| 2082 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2083 | | - pr_err("VIF%u.%u: CMD failed: %u\n", |
|---|
| 2084 | | - vif->mac->macid, vif->vifid, res_code); |
|---|
| 2085 | | - ret = -EFAULT; |
|---|
| 1809 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 1810 | + if (ret) |
|---|
| 2086 | 1811 | goto out; |
|---|
| 2087 | | - } |
|---|
| 2088 | 1812 | |
|---|
| 2089 | 1813 | out: |
|---|
| 2090 | 1814 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 1815 | + |
|---|
| 2091 | 1816 | return ret; |
|---|
| 2092 | 1817 | } |
|---|
| 2093 | 1818 | |
|---|
| .. | .. |
|---|
| 2096 | 1821 | { |
|---|
| 2097 | 1822 | struct sk_buff *cmd_skb; |
|---|
| 2098 | 1823 | struct qlink_cmd_set_def_key *cmd; |
|---|
| 2099 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2100 | 1824 | int ret = 0; |
|---|
| 2101 | 1825 | |
|---|
| 2102 | 1826 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2111 | 1835 | cmd->key_index = key_index; |
|---|
| 2112 | 1836 | cmd->unicast = unicast; |
|---|
| 2113 | 1837 | cmd->multicast = multicast; |
|---|
| 2114 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2115 | | - if (unlikely(ret)) |
|---|
| 2116 | | - goto out; |
|---|
| 2117 | 1838 | |
|---|
| 2118 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2119 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 2120 | | - vif->vifid, res_code); |
|---|
| 2121 | | - ret = -EFAULT; |
|---|
| 1839 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 1840 | + if (ret) |
|---|
| 2122 | 1841 | goto out; |
|---|
| 2123 | | - } |
|---|
| 2124 | 1842 | |
|---|
| 2125 | 1843 | out: |
|---|
| 2126 | 1844 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 1845 | + |
|---|
| 2127 | 1846 | return ret; |
|---|
| 2128 | 1847 | } |
|---|
| 2129 | 1848 | |
|---|
| .. | .. |
|---|
| 2131 | 1850 | { |
|---|
| 2132 | 1851 | struct sk_buff *cmd_skb; |
|---|
| 2133 | 1852 | struct qlink_cmd_set_def_mgmt_key *cmd; |
|---|
| 2134 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2135 | 1853 | int ret = 0; |
|---|
| 2136 | 1854 | |
|---|
| 2137 | 1855 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2144 | 1862 | |
|---|
| 2145 | 1863 | cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data; |
|---|
| 2146 | 1864 | cmd->key_index = key_index; |
|---|
| 2147 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2148 | | - if (unlikely(ret)) |
|---|
| 2149 | | - goto out; |
|---|
| 2150 | 1865 | |
|---|
| 2151 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2152 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 2153 | | - vif->vifid, res_code); |
|---|
| 2154 | | - ret = -EFAULT; |
|---|
| 1866 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 1867 | + if (ret) |
|---|
| 2155 | 1868 | goto out; |
|---|
| 2156 | | - } |
|---|
| 2157 | 1869 | |
|---|
| 2158 | 1870 | out: |
|---|
| 2159 | 1871 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 1872 | + |
|---|
| 2160 | 1873 | return ret; |
|---|
| 2161 | 1874 | } |
|---|
| 2162 | 1875 | |
|---|
| .. | .. |
|---|
| 2186 | 1899 | { |
|---|
| 2187 | 1900 | struct sk_buff *cmd_skb; |
|---|
| 2188 | 1901 | struct qlink_cmd_change_sta *cmd; |
|---|
| 2189 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2190 | 1902 | int ret = 0; |
|---|
| 2191 | 1903 | |
|---|
| 2192 | 1904 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2218 | 1930 | goto out; |
|---|
| 2219 | 1931 | } |
|---|
| 2220 | 1932 | |
|---|
| 2221 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2222 | | - if (unlikely(ret)) |
|---|
| 1933 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 1934 | + if (ret) |
|---|
| 2223 | 1935 | goto out; |
|---|
| 2224 | | - |
|---|
| 2225 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2226 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 2227 | | - vif->vifid, res_code); |
|---|
| 2228 | | - ret = -EFAULT; |
|---|
| 2229 | | - goto out; |
|---|
| 2230 | | - } |
|---|
| 2231 | 1936 | |
|---|
| 2232 | 1937 | out: |
|---|
| 2233 | 1938 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 1939 | + |
|---|
| 2234 | 1940 | return ret; |
|---|
| 2235 | 1941 | } |
|---|
| 2236 | 1942 | |
|---|
| .. | .. |
|---|
| 2239 | 1945 | { |
|---|
| 2240 | 1946 | struct sk_buff *cmd_skb; |
|---|
| 2241 | 1947 | struct qlink_cmd_del_sta *cmd; |
|---|
| 2242 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2243 | 1948 | int ret = 0; |
|---|
| 2244 | 1949 | |
|---|
| 2245 | 1950 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2260 | 1965 | cmd->subtype = params->subtype; |
|---|
| 2261 | 1966 | cmd->reason_code = cpu_to_le16(params->reason_code); |
|---|
| 2262 | 1967 | |
|---|
| 2263 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2264 | | - if (unlikely(ret)) |
|---|
| 1968 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 1969 | + if (ret) |
|---|
| 2265 | 1970 | goto out; |
|---|
| 2266 | | - |
|---|
| 2267 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2268 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 2269 | | - vif->vifid, res_code); |
|---|
| 2270 | | - ret = -EFAULT; |
|---|
| 2271 | | - goto out; |
|---|
| 2272 | | - } |
|---|
| 2273 | 1971 | |
|---|
| 2274 | 1972 | out: |
|---|
| 2275 | 1973 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 1974 | + |
|---|
| 2276 | 1975 | return ret; |
|---|
| 2277 | 1976 | } |
|---|
| 2278 | 1977 | |
|---|
| 2279 | 1978 | static void qtnf_cmd_channel_tlv_add(struct sk_buff *cmd_skb, |
|---|
| 2280 | 1979 | const struct ieee80211_channel *sc) |
|---|
| 2281 | 1980 | { |
|---|
| 2282 | | - struct qlink_tlv_channel *qchan; |
|---|
| 2283 | | - u32 flags = 0; |
|---|
| 1981 | + struct qlink_tlv_channel *tlv; |
|---|
| 1982 | + struct qlink_channel *qch; |
|---|
| 2284 | 1983 | |
|---|
| 2285 | | - qchan = skb_put_zero(cmd_skb, sizeof(*qchan)); |
|---|
| 2286 | | - qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); |
|---|
| 2287 | | - qchan->hdr.len = cpu_to_le16(sizeof(*qchan) - sizeof(qchan->hdr)); |
|---|
| 2288 | | - qchan->chan.center_freq = cpu_to_le16(sc->center_freq); |
|---|
| 2289 | | - qchan->chan.hw_value = cpu_to_le16(sc->hw_value); |
|---|
| 1984 | + tlv = skb_put_zero(cmd_skb, sizeof(*tlv)); |
|---|
| 1985 | + qch = &tlv->chan; |
|---|
| 1986 | + tlv->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); |
|---|
| 1987 | + tlv->hdr.len = cpu_to_le16(sizeof(*qch)); |
|---|
| 2290 | 1988 | |
|---|
| 2291 | | - if (sc->flags & IEEE80211_CHAN_NO_IR) |
|---|
| 2292 | | - flags |= QLINK_CHAN_NO_IR; |
|---|
| 2293 | | - |
|---|
| 2294 | | - if (sc->flags & IEEE80211_CHAN_RADAR) |
|---|
| 2295 | | - flags |= QLINK_CHAN_RADAR; |
|---|
| 2296 | | - |
|---|
| 2297 | | - qchan->chan.flags = cpu_to_le32(flags); |
|---|
| 1989 | + qch->center_freq = cpu_to_le16(sc->center_freq); |
|---|
| 1990 | + qch->hw_value = cpu_to_le16(sc->hw_value); |
|---|
| 1991 | + qch->band = qlink_utils_band_cfg2q(sc->band); |
|---|
| 1992 | + qch->max_power = sc->max_power; |
|---|
| 1993 | + qch->max_reg_power = sc->max_reg_power; |
|---|
| 1994 | + qch->max_antenna_gain = sc->max_antenna_gain; |
|---|
| 1995 | + qch->beacon_found = sc->beacon_found; |
|---|
| 1996 | + qch->dfs_state = qlink_utils_dfs_state_cfg2q(sc->dfs_state); |
|---|
| 1997 | + qch->flags = cpu_to_le32(qlink_utils_chflags_cfg2q(sc->flags)); |
|---|
| 2298 | 1998 | } |
|---|
| 2299 | 1999 | |
|---|
| 2300 | 2000 | static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb, |
|---|
| .. | .. |
|---|
| 2315 | 2015 | |
|---|
| 2316 | 2016 | int qtnf_cmd_send_scan(struct qtnf_wmac *mac) |
|---|
| 2317 | 2017 | { |
|---|
| 2318 | | - struct sk_buff *cmd_skb; |
|---|
| 2319 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2320 | | - struct ieee80211_channel *sc; |
|---|
| 2321 | 2018 | struct cfg80211_scan_request *scan_req = mac->scan_req; |
|---|
| 2322 | | - int n_channels; |
|---|
| 2323 | | - int count = 0; |
|---|
| 2019 | + u16 dwell_passive = QTNF_SCAN_DWELL_PASSIVE_DEFAULT; |
|---|
| 2020 | + u16 dwell_active = QTNF_SCAN_DWELL_ACTIVE_DEFAULT; |
|---|
| 2021 | + struct wireless_dev *wdev = scan_req->wdev; |
|---|
| 2022 | + struct ieee80211_channel *sc; |
|---|
| 2023 | + struct qlink_cmd_scan *cmd; |
|---|
| 2024 | + struct sk_buff *cmd_skb; |
|---|
| 2025 | + int n_channels = 0; |
|---|
| 2026 | + u64 flags = 0; |
|---|
| 2027 | + int count; |
|---|
| 2324 | 2028 | int ret; |
|---|
| 2325 | 2029 | |
|---|
| 2326 | 2030 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, |
|---|
| 2327 | 2031 | QLINK_CMD_SCAN, |
|---|
| 2328 | | - sizeof(struct qlink_cmd)); |
|---|
| 2032 | + sizeof(*cmd)); |
|---|
| 2329 | 2033 | if (!cmd_skb) |
|---|
| 2330 | 2034 | return -ENOMEM; |
|---|
| 2331 | 2035 | |
|---|
| 2332 | | - qtnf_bus_lock(mac->bus); |
|---|
| 2036 | + cmd = (struct qlink_cmd_scan *)cmd_skb->data; |
|---|
| 2333 | 2037 | |
|---|
| 2334 | | - if (scan_req->n_ssids != 0) { |
|---|
| 2335 | | - while (count < scan_req->n_ssids) { |
|---|
| 2336 | | - qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, |
|---|
| 2337 | | - scan_req->ssids[count].ssid, |
|---|
| 2338 | | - scan_req->ssids[count].ssid_len); |
|---|
| 2339 | | - count++; |
|---|
| 2340 | | - } |
|---|
| 2038 | + if (scan_req->duration) { |
|---|
| 2039 | + dwell_active = scan_req->duration; |
|---|
| 2040 | + dwell_passive = scan_req->duration; |
|---|
| 2041 | + } else if (wdev->iftype == NL80211_IFTYPE_STATION && |
|---|
| 2042 | + wdev->current_bss) { |
|---|
| 2043 | + /* let device select dwell based on traffic conditions */ |
|---|
| 2044 | + dwell_active = QTNF_SCAN_TIME_AUTO; |
|---|
| 2045 | + dwell_passive = QTNF_SCAN_TIME_AUTO; |
|---|
| 2046 | + } |
|---|
| 2047 | + |
|---|
| 2048 | + cmd->n_ssids = cpu_to_le16(scan_req->n_ssids); |
|---|
| 2049 | + for (count = 0; count < scan_req->n_ssids; ++count) { |
|---|
| 2050 | + qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, |
|---|
| 2051 | + scan_req->ssids[count].ssid, |
|---|
| 2052 | + scan_req->ssids[count].ssid_len); |
|---|
| 2341 | 2053 | } |
|---|
| 2342 | 2054 | |
|---|
| 2343 | 2055 | if (scan_req->ie_len != 0) |
|---|
| 2344 | 2056 | qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_PROBE_REQ, |
|---|
| 2345 | 2057 | scan_req->ie, scan_req->ie_len); |
|---|
| 2346 | 2058 | |
|---|
| 2347 | | - if (scan_req->n_channels) { |
|---|
| 2348 | | - n_channels = scan_req->n_channels; |
|---|
| 2349 | | - count = 0; |
|---|
| 2059 | + for (count = 0; count < scan_req->n_channels; ++count) { |
|---|
| 2060 | + sc = scan_req->channels[count]; |
|---|
| 2061 | + if (sc->flags & IEEE80211_CHAN_DISABLED) |
|---|
| 2062 | + continue; |
|---|
| 2350 | 2063 | |
|---|
| 2351 | | - while (n_channels != 0) { |
|---|
| 2352 | | - sc = scan_req->channels[count]; |
|---|
| 2353 | | - if (sc->flags & IEEE80211_CHAN_DISABLED) { |
|---|
| 2354 | | - n_channels--; |
|---|
| 2355 | | - continue; |
|---|
| 2356 | | - } |
|---|
| 2064 | + pr_debug("[MAC%u] scan chan=%d, freq=%d, flags=%#x\n", |
|---|
| 2065 | + mac->macid, sc->hw_value, sc->center_freq, |
|---|
| 2066 | + sc->flags); |
|---|
| 2357 | 2067 | |
|---|
| 2358 | | - pr_debug("MAC%u: scan chan=%d, freq=%d, flags=%#x\n", |
|---|
| 2359 | | - mac->macid, sc->hw_value, sc->center_freq, |
|---|
| 2360 | | - sc->flags); |
|---|
| 2361 | | - |
|---|
| 2362 | | - qtnf_cmd_channel_tlv_add(cmd_skb, sc); |
|---|
| 2363 | | - n_channels--; |
|---|
| 2364 | | - count++; |
|---|
| 2365 | | - } |
|---|
| 2068 | + qtnf_cmd_channel_tlv_add(cmd_skb, sc); |
|---|
| 2069 | + ++n_channels; |
|---|
| 2366 | 2070 | } |
|---|
| 2367 | 2071 | |
|---|
| 2072 | + if (scan_req->flags & NL80211_SCAN_FLAG_FLUSH) |
|---|
| 2073 | + flags |= QLINK_SCAN_FLAG_FLUSH; |
|---|
| 2074 | + |
|---|
| 2075 | + if (scan_req->duration_mandatory) |
|---|
| 2076 | + flags |= QLINK_SCAN_FLAG_DURATION_MANDATORY; |
|---|
| 2077 | + |
|---|
| 2078 | + cmd->n_channels = cpu_to_le16(n_channels); |
|---|
| 2079 | + cmd->active_dwell = cpu_to_le16(dwell_active); |
|---|
| 2080 | + cmd->passive_dwell = cpu_to_le16(dwell_passive); |
|---|
| 2081 | + cmd->sample_duration = cpu_to_le16(QTNF_SCAN_SAMPLE_DURATION_DEFAULT); |
|---|
| 2082 | + cmd->flags = cpu_to_le64(flags); |
|---|
| 2083 | + |
|---|
| 2084 | + pr_debug("[MAC%u] %s scan dwell active=%u passive=%u duration=%u\n", |
|---|
| 2085 | + mac->macid, |
|---|
| 2086 | + scan_req->duration_mandatory ? "mandatory" : "max", |
|---|
| 2087 | + dwell_active, dwell_passive, |
|---|
| 2088 | + QTNF_SCAN_SAMPLE_DURATION_DEFAULT); |
|---|
| 2089 | + |
|---|
| 2368 | 2090 | if (scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { |
|---|
| 2369 | | - pr_debug("MAC%u: scan with random addr=%pM, mask=%pM\n", |
|---|
| 2091 | + pr_debug("[MAC%u] scan with random addr=%pM, mask=%pM\n", |
|---|
| 2370 | 2092 | mac->macid, |
|---|
| 2371 | 2093 | scan_req->mac_addr, scan_req->mac_addr_mask); |
|---|
| 2372 | | - |
|---|
| 2373 | 2094 | qtnf_cmd_randmac_tlv_add(cmd_skb, scan_req->mac_addr, |
|---|
| 2374 | 2095 | scan_req->mac_addr_mask); |
|---|
| 2375 | 2096 | } |
|---|
| 2376 | 2097 | |
|---|
| 2377 | | - ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); |
|---|
| 2378 | | - |
|---|
| 2379 | | - if (unlikely(ret)) |
|---|
| 2380 | | - goto out; |
|---|
| 2381 | | - |
|---|
| 2382 | | - pr_debug("MAC%u: scan started\n", mac->macid); |
|---|
| 2383 | | - |
|---|
| 2384 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2385 | | - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); |
|---|
| 2386 | | - ret = -EFAULT; |
|---|
| 2387 | | - goto out; |
|---|
| 2388 | | - } |
|---|
| 2389 | | -out: |
|---|
| 2098 | + qtnf_bus_lock(mac->bus); |
|---|
| 2099 | + ret = qtnf_cmd_send(mac->bus, cmd_skb); |
|---|
| 2390 | 2100 | qtnf_bus_unlock(mac->bus); |
|---|
| 2101 | + |
|---|
| 2391 | 2102 | return ret; |
|---|
| 2392 | 2103 | } |
|---|
| 2393 | 2104 | |
|---|
| .. | .. |
|---|
| 2397 | 2108 | struct sk_buff *cmd_skb; |
|---|
| 2398 | 2109 | struct qlink_cmd_connect *cmd; |
|---|
| 2399 | 2110 | struct qlink_auth_encr *aen; |
|---|
| 2400 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2401 | 2111 | int ret; |
|---|
| 2402 | 2112 | int i; |
|---|
| 2403 | 2113 | u32 connect_flags = 0; |
|---|
| .. | .. |
|---|
| 2478 | 2188 | qtnf_cmd_channel_tlv_add(cmd_skb, sme->channel); |
|---|
| 2479 | 2189 | |
|---|
| 2480 | 2190 | qtnf_bus_lock(vif->mac->bus); |
|---|
| 2481 | | - |
|---|
| 2482 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2483 | | - |
|---|
| 2484 | | - if (unlikely(ret)) |
|---|
| 2191 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 2192 | + if (ret) |
|---|
| 2485 | 2193 | goto out; |
|---|
| 2486 | 2194 | |
|---|
| 2487 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2488 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 2489 | | - vif->vifid, res_code); |
|---|
| 2490 | | - ret = -EFAULT; |
|---|
| 2491 | | - goto out; |
|---|
| 2492 | | - } |
|---|
| 2493 | 2195 | out: |
|---|
| 2494 | 2196 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 2197 | + |
|---|
| 2198 | + return ret; |
|---|
| 2199 | +} |
|---|
| 2200 | + |
|---|
| 2201 | +int qtnf_cmd_send_external_auth(struct qtnf_vif *vif, |
|---|
| 2202 | + struct cfg80211_external_auth_params *auth) |
|---|
| 2203 | +{ |
|---|
| 2204 | + struct sk_buff *cmd_skb; |
|---|
| 2205 | + struct qlink_cmd_external_auth *cmd; |
|---|
| 2206 | + int ret; |
|---|
| 2207 | + |
|---|
| 2208 | + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| 2209 | + QLINK_CMD_EXTERNAL_AUTH, |
|---|
| 2210 | + sizeof(*cmd)); |
|---|
| 2211 | + if (!cmd_skb) |
|---|
| 2212 | + return -ENOMEM; |
|---|
| 2213 | + |
|---|
| 2214 | + cmd = (struct qlink_cmd_external_auth *)cmd_skb->data; |
|---|
| 2215 | + |
|---|
| 2216 | + ether_addr_copy(cmd->peer, auth->bssid); |
|---|
| 2217 | + cmd->status = cpu_to_le16(auth->status); |
|---|
| 2218 | + |
|---|
| 2219 | + qtnf_bus_lock(vif->mac->bus); |
|---|
| 2220 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 2221 | + if (ret) |
|---|
| 2222 | + goto out; |
|---|
| 2223 | + |
|---|
| 2224 | +out: |
|---|
| 2225 | + qtnf_bus_unlock(vif->mac->bus); |
|---|
| 2226 | + |
|---|
| 2495 | 2227 | return ret; |
|---|
| 2496 | 2228 | } |
|---|
| 2497 | 2229 | |
|---|
| .. | .. |
|---|
| 2499 | 2231 | { |
|---|
| 2500 | 2232 | struct sk_buff *cmd_skb; |
|---|
| 2501 | 2233 | struct qlink_cmd_disconnect *cmd; |
|---|
| 2502 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2503 | 2234 | int ret; |
|---|
| 2504 | 2235 | |
|---|
| 2505 | 2236 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2513 | 2244 | cmd = (struct qlink_cmd_disconnect *)cmd_skb->data; |
|---|
| 2514 | 2245 | cmd->reason = cpu_to_le16(reason_code); |
|---|
| 2515 | 2246 | |
|---|
| 2516 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2517 | | - |
|---|
| 2518 | | - if (unlikely(ret)) |
|---|
| 2247 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 2248 | + if (ret) |
|---|
| 2519 | 2249 | goto out; |
|---|
| 2520 | 2250 | |
|---|
| 2521 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2522 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 2523 | | - vif->vifid, res_code); |
|---|
| 2524 | | - ret = -EFAULT; |
|---|
| 2525 | | - goto out; |
|---|
| 2526 | | - } |
|---|
| 2527 | 2251 | out: |
|---|
| 2528 | 2252 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 2253 | + |
|---|
| 2529 | 2254 | return ret; |
|---|
| 2530 | 2255 | } |
|---|
| 2531 | 2256 | |
|---|
| .. | .. |
|---|
| 2533 | 2258 | { |
|---|
| 2534 | 2259 | struct sk_buff *cmd_skb; |
|---|
| 2535 | 2260 | struct qlink_cmd_updown *cmd; |
|---|
| 2536 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2537 | 2261 | int ret; |
|---|
| 2538 | 2262 | |
|---|
| 2539 | 2263 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2546 | 2270 | cmd->if_up = !!up; |
|---|
| 2547 | 2271 | |
|---|
| 2548 | 2272 | qtnf_bus_lock(vif->mac->bus); |
|---|
| 2549 | | - |
|---|
| 2550 | | - ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); |
|---|
| 2551 | | - |
|---|
| 2552 | | - if (unlikely(ret)) |
|---|
| 2273 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 2274 | + if (ret) |
|---|
| 2553 | 2275 | goto out; |
|---|
| 2554 | 2276 | |
|---|
| 2555 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2556 | | - pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, |
|---|
| 2557 | | - vif->vifid, res_code); |
|---|
| 2558 | | - ret = -EFAULT; |
|---|
| 2559 | | - goto out; |
|---|
| 2560 | | - } |
|---|
| 2561 | 2277 | out: |
|---|
| 2562 | 2278 | qtnf_bus_unlock(vif->mac->bus); |
|---|
| 2279 | + |
|---|
| 2563 | 2280 | return ret; |
|---|
| 2564 | 2281 | } |
|---|
| 2565 | 2282 | |
|---|
| 2566 | | -int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req) |
|---|
| 2283 | +int qtnf_cmd_reg_notify(struct qtnf_wmac *mac, struct regulatory_request *req, |
|---|
| 2284 | + bool slave_radar, bool dfs_offload) |
|---|
| 2567 | 2285 | { |
|---|
| 2286 | + struct wiphy *wiphy = priv_to_wiphy(mac); |
|---|
| 2287 | + struct qtnf_bus *bus = mac->bus; |
|---|
| 2568 | 2288 | struct sk_buff *cmd_skb; |
|---|
| 2569 | 2289 | int ret; |
|---|
| 2570 | | - u16 res_code; |
|---|
| 2571 | 2290 | struct qlink_cmd_reg_notify *cmd; |
|---|
| 2291 | + enum nl80211_band band; |
|---|
| 2292 | + const struct ieee80211_supported_band *cfg_band; |
|---|
| 2572 | 2293 | |
|---|
| 2573 | | - cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, |
|---|
| 2294 | + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, |
|---|
| 2574 | 2295 | QLINK_CMD_REG_NOTIFY, |
|---|
| 2575 | 2296 | sizeof(*cmd)); |
|---|
| 2576 | 2297 | if (!cmd_skb) |
|---|
| .. | .. |
|---|
| 2607 | 2328 | break; |
|---|
| 2608 | 2329 | } |
|---|
| 2609 | 2330 | |
|---|
| 2610 | | - qtnf_bus_lock(bus); |
|---|
| 2611 | | - |
|---|
| 2612 | | - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); |
|---|
| 2613 | | - if (ret) |
|---|
| 2614 | | - goto out; |
|---|
| 2615 | | - |
|---|
| 2616 | | - switch (res_code) { |
|---|
| 2617 | | - case QLINK_CMD_RESULT_ENOTSUPP: |
|---|
| 2618 | | - pr_warn("reg update not supported\n"); |
|---|
| 2619 | | - ret = -EOPNOTSUPP; |
|---|
| 2331 | + switch (req->dfs_region) { |
|---|
| 2332 | + case NL80211_DFS_FCC: |
|---|
| 2333 | + cmd->dfs_region = QLINK_DFS_FCC; |
|---|
| 2620 | 2334 | break; |
|---|
| 2621 | | - case QLINK_CMD_RESULT_EALREADY: |
|---|
| 2622 | | - pr_info("regulatory domain is already set to %c%c", |
|---|
| 2623 | | - req->alpha2[0], req->alpha2[1]); |
|---|
| 2624 | | - ret = -EALREADY; |
|---|
| 2335 | + case NL80211_DFS_ETSI: |
|---|
| 2336 | + cmd->dfs_region = QLINK_DFS_ETSI; |
|---|
| 2625 | 2337 | break; |
|---|
| 2626 | | - case QLINK_CMD_RESULT_OK: |
|---|
| 2627 | | - ret = 0; |
|---|
| 2338 | + case NL80211_DFS_JP: |
|---|
| 2339 | + cmd->dfs_region = QLINK_DFS_JP; |
|---|
| 2628 | 2340 | break; |
|---|
| 2629 | 2341 | default: |
|---|
| 2630 | | - ret = -EFAULT; |
|---|
| 2342 | + cmd->dfs_region = QLINK_DFS_UNSET; |
|---|
| 2631 | 2343 | break; |
|---|
| 2632 | 2344 | } |
|---|
| 2633 | 2345 | |
|---|
| 2634 | | -out: |
|---|
| 2346 | + cmd->slave_radar = slave_radar; |
|---|
| 2347 | + cmd->dfs_offload = dfs_offload; |
|---|
| 2348 | + cmd->num_channels = 0; |
|---|
| 2349 | + |
|---|
| 2350 | + for (band = 0; band < NUM_NL80211_BANDS; band++) { |
|---|
| 2351 | + unsigned int i; |
|---|
| 2352 | + |
|---|
| 2353 | + cfg_band = wiphy->bands[band]; |
|---|
| 2354 | + if (!cfg_band) |
|---|
| 2355 | + continue; |
|---|
| 2356 | + |
|---|
| 2357 | + cmd->num_channels += cfg_band->n_channels; |
|---|
| 2358 | + |
|---|
| 2359 | + for (i = 0; i < cfg_band->n_channels; ++i) { |
|---|
| 2360 | + qtnf_cmd_channel_tlv_add(cmd_skb, |
|---|
| 2361 | + &cfg_band->channels[i]); |
|---|
| 2362 | + } |
|---|
| 2363 | + } |
|---|
| 2364 | + |
|---|
| 2365 | + qtnf_bus_lock(bus); |
|---|
| 2366 | + ret = qtnf_cmd_send(bus, cmd_skb); |
|---|
| 2635 | 2367 | qtnf_bus_unlock(bus); |
|---|
| 2636 | 2368 | |
|---|
| 2637 | 2369 | return ret; |
|---|
| 2638 | 2370 | } |
|---|
| 2639 | 2371 | |
|---|
| 2640 | | -int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel, |
|---|
| 2641 | | - struct qtnf_chan_stats *stats) |
|---|
| 2372 | +static int |
|---|
| 2373 | +qtnf_cmd_resp_proc_chan_stat_info(struct survey_info *survey, |
|---|
| 2374 | + const u8 *payload, size_t payload_len) |
|---|
| 2375 | +{ |
|---|
| 2376 | + const struct qlink_chan_stats *stats = NULL; |
|---|
| 2377 | + const struct qlink_tlv_hdr *tlv; |
|---|
| 2378 | + u16 tlv_value_len; |
|---|
| 2379 | + u16 tlv_type; |
|---|
| 2380 | + const u8 *map = NULL; |
|---|
| 2381 | + unsigned int map_len = 0; |
|---|
| 2382 | + unsigned int stats_len = 0; |
|---|
| 2383 | + |
|---|
| 2384 | + qlink_for_each_tlv(tlv, payload, payload_len) { |
|---|
| 2385 | + tlv_type = le16_to_cpu(tlv->type); |
|---|
| 2386 | + tlv_value_len = le16_to_cpu(tlv->len); |
|---|
| 2387 | + |
|---|
| 2388 | + switch (tlv_type) { |
|---|
| 2389 | + case QTN_TLV_ID_BITMAP: |
|---|
| 2390 | + map = tlv->val; |
|---|
| 2391 | + map_len = tlv_value_len; |
|---|
| 2392 | + break; |
|---|
| 2393 | + case QTN_TLV_ID_CHANNEL_STATS: |
|---|
| 2394 | + stats = (struct qlink_chan_stats *)tlv->val; |
|---|
| 2395 | + stats_len = tlv_value_len; |
|---|
| 2396 | + break; |
|---|
| 2397 | + default: |
|---|
| 2398 | + pr_info("Unknown TLV type: %#x\n", tlv_type); |
|---|
| 2399 | + break; |
|---|
| 2400 | + } |
|---|
| 2401 | + } |
|---|
| 2402 | + |
|---|
| 2403 | + if (!qlink_tlv_parsing_ok(tlv, payload, payload_len)) { |
|---|
| 2404 | + pr_err("Malformed TLV buffer\n"); |
|---|
| 2405 | + return -EINVAL; |
|---|
| 2406 | + } |
|---|
| 2407 | + |
|---|
| 2408 | + if (!map || !stats) |
|---|
| 2409 | + return 0; |
|---|
| 2410 | + |
|---|
| 2411 | +#define qtnf_chan_stat_avail(stat_name, bitn) \ |
|---|
| 2412 | + (qtnf_utils_is_bit_set(map, bitn, map_len) && \ |
|---|
| 2413 | + (offsetofend(struct qlink_chan_stats, stat_name) <= stats_len)) |
|---|
| 2414 | + |
|---|
| 2415 | + if (qtnf_chan_stat_avail(time_on, QLINK_CHAN_STAT_TIME_ON)) { |
|---|
| 2416 | + survey->filled |= SURVEY_INFO_TIME; |
|---|
| 2417 | + survey->time = le64_to_cpu(stats->time_on); |
|---|
| 2418 | + } |
|---|
| 2419 | + |
|---|
| 2420 | + if (qtnf_chan_stat_avail(time_tx, QLINK_CHAN_STAT_TIME_TX)) { |
|---|
| 2421 | + survey->filled |= SURVEY_INFO_TIME_TX; |
|---|
| 2422 | + survey->time_tx = le64_to_cpu(stats->time_tx); |
|---|
| 2423 | + } |
|---|
| 2424 | + |
|---|
| 2425 | + if (qtnf_chan_stat_avail(time_rx, QLINK_CHAN_STAT_TIME_RX)) { |
|---|
| 2426 | + survey->filled |= SURVEY_INFO_TIME_RX; |
|---|
| 2427 | + survey->time_rx = le64_to_cpu(stats->time_rx); |
|---|
| 2428 | + } |
|---|
| 2429 | + |
|---|
| 2430 | + if (qtnf_chan_stat_avail(cca_busy, QLINK_CHAN_STAT_CCA_BUSY)) { |
|---|
| 2431 | + survey->filled |= SURVEY_INFO_TIME_BUSY; |
|---|
| 2432 | + survey->time_busy = le64_to_cpu(stats->cca_busy); |
|---|
| 2433 | + } |
|---|
| 2434 | + |
|---|
| 2435 | + if (qtnf_chan_stat_avail(cca_busy_ext, QLINK_CHAN_STAT_CCA_BUSY_EXT)) { |
|---|
| 2436 | + survey->filled |= SURVEY_INFO_TIME_EXT_BUSY; |
|---|
| 2437 | + survey->time_ext_busy = le64_to_cpu(stats->cca_busy_ext); |
|---|
| 2438 | + } |
|---|
| 2439 | + |
|---|
| 2440 | + if (qtnf_chan_stat_avail(time_scan, QLINK_CHAN_STAT_TIME_SCAN)) { |
|---|
| 2441 | + survey->filled |= SURVEY_INFO_TIME_SCAN; |
|---|
| 2442 | + survey->time_scan = le64_to_cpu(stats->time_scan); |
|---|
| 2443 | + } |
|---|
| 2444 | + |
|---|
| 2445 | + if (qtnf_chan_stat_avail(chan_noise, QLINK_CHAN_STAT_CHAN_NOISE)) { |
|---|
| 2446 | + survey->filled |= SURVEY_INFO_NOISE_DBM; |
|---|
| 2447 | + survey->noise = stats->chan_noise; |
|---|
| 2448 | + } |
|---|
| 2449 | + |
|---|
| 2450 | +#undef qtnf_chan_stat_avail |
|---|
| 2451 | + |
|---|
| 2452 | + return 0; |
|---|
| 2453 | +} |
|---|
| 2454 | + |
|---|
| 2455 | +int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u32 chan_freq, |
|---|
| 2456 | + struct survey_info *survey) |
|---|
| 2642 | 2457 | { |
|---|
| 2643 | 2458 | struct sk_buff *cmd_skb, *resp_skb = NULL; |
|---|
| 2644 | 2459 | struct qlink_cmd_get_chan_stats *cmd; |
|---|
| 2645 | 2460 | struct qlink_resp_get_chan_stats *resp; |
|---|
| 2646 | | - size_t var_data_len; |
|---|
| 2647 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2461 | + size_t var_data_len = 0; |
|---|
| 2648 | 2462 | int ret = 0; |
|---|
| 2649 | 2463 | |
|---|
| 2650 | 2464 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, |
|---|
| .. | .. |
|---|
| 2653 | 2467 | if (!cmd_skb) |
|---|
| 2654 | 2468 | return -ENOMEM; |
|---|
| 2655 | 2469 | |
|---|
| 2656 | | - qtnf_bus_lock(mac->bus); |
|---|
| 2657 | | - |
|---|
| 2658 | 2470 | cmd = (struct qlink_cmd_get_chan_stats *)cmd_skb->data; |
|---|
| 2659 | | - cmd->channel = cpu_to_le16(channel); |
|---|
| 2471 | + cmd->channel_freq = cpu_to_le32(chan_freq); |
|---|
| 2660 | 2472 | |
|---|
| 2661 | | - ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, |
|---|
| 2473 | + qtnf_bus_lock(mac->bus); |
|---|
| 2474 | + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, |
|---|
| 2662 | 2475 | sizeof(*resp), &var_data_len); |
|---|
| 2663 | | - if (unlikely(ret)) { |
|---|
| 2664 | | - qtnf_bus_unlock(mac->bus); |
|---|
| 2665 | | - return ret; |
|---|
| 2666 | | - } |
|---|
| 2476 | + qtnf_bus_unlock(mac->bus); |
|---|
| 2667 | 2477 | |
|---|
| 2668 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2669 | | - switch (res_code) { |
|---|
| 2670 | | - case QLINK_CMD_RESULT_ENOTFOUND: |
|---|
| 2671 | | - ret = -ENOENT; |
|---|
| 2672 | | - break; |
|---|
| 2673 | | - default: |
|---|
| 2674 | | - pr_err("cmd exec failed: 0x%.4X\n", res_code); |
|---|
| 2675 | | - ret = -EFAULT; |
|---|
| 2676 | | - break; |
|---|
| 2677 | | - } |
|---|
| 2478 | + if (ret) |
|---|
| 2479 | + goto out; |
|---|
| 2480 | + |
|---|
| 2481 | + resp = (struct qlink_resp_get_chan_stats *)resp_skb->data; |
|---|
| 2482 | + |
|---|
| 2483 | + if (le32_to_cpu(resp->chan_freq) != chan_freq) { |
|---|
| 2484 | + pr_err("[MAC%u] channel stats freq %u != requested %u\n", |
|---|
| 2485 | + mac->macid, le32_to_cpu(resp->chan_freq), chan_freq); |
|---|
| 2486 | + ret = -EINVAL; |
|---|
| 2678 | 2487 | goto out; |
|---|
| 2679 | 2488 | } |
|---|
| 2680 | 2489 | |
|---|
| 2681 | | - resp = (struct qlink_resp_get_chan_stats *)resp_skb->data; |
|---|
| 2682 | | - ret = qtnf_cmd_resp_proc_chan_stat_info(stats, resp->info, |
|---|
| 2490 | + ret = qtnf_cmd_resp_proc_chan_stat_info(survey, resp->info, |
|---|
| 2683 | 2491 | var_data_len); |
|---|
| 2684 | 2492 | |
|---|
| 2685 | 2493 | out: |
|---|
| 2686 | | - qtnf_bus_unlock(mac->bus); |
|---|
| 2687 | 2494 | consume_skb(resp_skb); |
|---|
| 2495 | + |
|---|
| 2688 | 2496 | return ret; |
|---|
| 2689 | 2497 | } |
|---|
| 2690 | 2498 | |
|---|
| .. | .. |
|---|
| 2694 | 2502 | struct qtnf_wmac *mac = vif->mac; |
|---|
| 2695 | 2503 | struct qlink_cmd_chan_switch *cmd; |
|---|
| 2696 | 2504 | struct sk_buff *cmd_skb; |
|---|
| 2697 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2698 | 2505 | int ret; |
|---|
| 2506 | + u64 flags = 0; |
|---|
| 2699 | 2507 | |
|---|
| 2700 | 2508 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid, |
|---|
| 2701 | 2509 | QLINK_CMD_CHAN_SWITCH, |
|---|
| .. | .. |
|---|
| 2703 | 2511 | if (!cmd_skb) |
|---|
| 2704 | 2512 | return -ENOMEM; |
|---|
| 2705 | 2513 | |
|---|
| 2706 | | - qtnf_bus_lock(mac->bus); |
|---|
| 2514 | + if (params->radar_required) |
|---|
| 2515 | + flags |= QLINK_CHAN_SW_RADAR_REQUIRED; |
|---|
| 2516 | + |
|---|
| 2517 | + if (params->block_tx) |
|---|
| 2518 | + flags |= QLINK_CHAN_SW_BLOCK_TX; |
|---|
| 2707 | 2519 | |
|---|
| 2708 | 2520 | cmd = (struct qlink_cmd_chan_switch *)cmd_skb->data; |
|---|
| 2709 | | - cmd->channel = cpu_to_le16(params->chandef.chan->hw_value); |
|---|
| 2710 | | - cmd->radar_required = params->radar_required; |
|---|
| 2711 | | - cmd->block_tx = params->block_tx; |
|---|
| 2521 | + qlink_chandef_cfg2q(¶ms->chandef, &cmd->channel); |
|---|
| 2522 | + cmd->flags = cpu_to_le64(flags); |
|---|
| 2712 | 2523 | cmd->beacon_count = params->count; |
|---|
| 2713 | 2524 | |
|---|
| 2714 | | - ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); |
|---|
| 2715 | | - |
|---|
| 2716 | | - if (unlikely(ret)) |
|---|
| 2717 | | - goto out; |
|---|
| 2718 | | - |
|---|
| 2719 | | - switch (res_code) { |
|---|
| 2720 | | - case QLINK_CMD_RESULT_OK: |
|---|
| 2721 | | - ret = 0; |
|---|
| 2722 | | - break; |
|---|
| 2723 | | - case QLINK_CMD_RESULT_ENOTFOUND: |
|---|
| 2724 | | - ret = -ENOENT; |
|---|
| 2725 | | - break; |
|---|
| 2726 | | - case QLINK_CMD_RESULT_ENOTSUPP: |
|---|
| 2727 | | - ret = -EOPNOTSUPP; |
|---|
| 2728 | | - break; |
|---|
| 2729 | | - case QLINK_CMD_RESULT_EALREADY: |
|---|
| 2730 | | - ret = -EALREADY; |
|---|
| 2731 | | - break; |
|---|
| 2732 | | - case QLINK_CMD_RESULT_INVALID: |
|---|
| 2733 | | - default: |
|---|
| 2734 | | - ret = -EFAULT; |
|---|
| 2735 | | - break; |
|---|
| 2736 | | - } |
|---|
| 2737 | | - |
|---|
| 2738 | | -out: |
|---|
| 2525 | + qtnf_bus_lock(mac->bus); |
|---|
| 2526 | + ret = qtnf_cmd_send(mac->bus, cmd_skb); |
|---|
| 2739 | 2527 | qtnf_bus_unlock(mac->bus); |
|---|
| 2528 | + |
|---|
| 2740 | 2529 | return ret; |
|---|
| 2741 | 2530 | } |
|---|
| 2742 | 2531 | |
|---|
| .. | .. |
|---|
| 2746 | 2535 | const struct qlink_resp_channel_get *resp; |
|---|
| 2747 | 2536 | struct sk_buff *cmd_skb; |
|---|
| 2748 | 2537 | struct sk_buff *resp_skb = NULL; |
|---|
| 2749 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2750 | 2538 | int ret; |
|---|
| 2751 | 2539 | |
|---|
| 2752 | 2540 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2756 | 2544 | return -ENOMEM; |
|---|
| 2757 | 2545 | |
|---|
| 2758 | 2546 | qtnf_bus_lock(bus); |
|---|
| 2759 | | - |
|---|
| 2760 | | - ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, |
|---|
| 2547 | + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, |
|---|
| 2761 | 2548 | sizeof(*resp), NULL); |
|---|
| 2762 | | - |
|---|
| 2763 | | - qtnf_bus_unlock(bus); |
|---|
| 2764 | | - |
|---|
| 2765 | | - if (unlikely(ret)) |
|---|
| 2549 | + if (ret) |
|---|
| 2766 | 2550 | goto out; |
|---|
| 2767 | | - |
|---|
| 2768 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2769 | | - ret = -ENODATA; |
|---|
| 2770 | | - goto out; |
|---|
| 2771 | | - } |
|---|
| 2772 | 2551 | |
|---|
| 2773 | 2552 | resp = (const struct qlink_resp_channel_get *)resp_skb->data; |
|---|
| 2774 | 2553 | qlink_chandef_q2cfg(priv_to_wiphy(vif->mac), &resp->chan, chdef); |
|---|
| 2775 | 2554 | |
|---|
| 2776 | 2555 | out: |
|---|
| 2556 | + qtnf_bus_unlock(bus); |
|---|
| 2777 | 2557 | consume_skb(resp_skb); |
|---|
| 2558 | + |
|---|
| 2778 | 2559 | return ret; |
|---|
| 2779 | 2560 | } |
|---|
| 2780 | 2561 | |
|---|
| .. | .. |
|---|
| 2786 | 2567 | struct sk_buff *cmd_skb; |
|---|
| 2787 | 2568 | struct qlink_cmd_start_cac *cmd; |
|---|
| 2788 | 2569 | int ret; |
|---|
| 2789 | | - u16 res_code; |
|---|
| 2790 | 2570 | |
|---|
| 2791 | 2571 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| 2792 | 2572 | QLINK_CMD_START_CAC, |
|---|
| .. | .. |
|---|
| 2799 | 2579 | qlink_chandef_cfg2q(chdef, &cmd->chan); |
|---|
| 2800 | 2580 | |
|---|
| 2801 | 2581 | qtnf_bus_lock(bus); |
|---|
| 2802 | | - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); |
|---|
| 2803 | | - qtnf_bus_unlock(bus); |
|---|
| 2804 | | - |
|---|
| 2582 | + ret = qtnf_cmd_send(bus, cmd_skb); |
|---|
| 2805 | 2583 | if (ret) |
|---|
| 2806 | | - return ret; |
|---|
| 2584 | + goto out; |
|---|
| 2807 | 2585 | |
|---|
| 2808 | | - switch (res_code) { |
|---|
| 2809 | | - case QLINK_CMD_RESULT_OK: |
|---|
| 2810 | | - break; |
|---|
| 2811 | | - default: |
|---|
| 2812 | | - ret = -EOPNOTSUPP; |
|---|
| 2813 | | - break; |
|---|
| 2814 | | - } |
|---|
| 2586 | +out: |
|---|
| 2587 | + qtnf_bus_unlock(bus); |
|---|
| 2815 | 2588 | |
|---|
| 2816 | 2589 | return ret; |
|---|
| 2817 | 2590 | } |
|---|
| .. | .. |
|---|
| 2822 | 2595 | struct qtnf_bus *bus = vif->mac->bus; |
|---|
| 2823 | 2596 | struct sk_buff *cmd_skb; |
|---|
| 2824 | 2597 | struct qlink_tlv_hdr *tlv; |
|---|
| 2825 | | - size_t acl_size = qtnf_cmd_acl_data_size(params); |
|---|
| 2826 | | - u16 res_code; |
|---|
| 2598 | + size_t acl_size = struct_size(params, mac_addrs, params->n_acl_entries); |
|---|
| 2827 | 2599 | int ret; |
|---|
| 2828 | 2600 | |
|---|
| 2829 | 2601 | cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| .. | .. |
|---|
| 2832 | 2604 | if (!cmd_skb) |
|---|
| 2833 | 2605 | return -ENOMEM; |
|---|
| 2834 | 2606 | |
|---|
| 2835 | | - tlv = skb_put(cmd_skb, sizeof(*tlv) + acl_size); |
|---|
| 2607 | + tlv = skb_put(cmd_skb, sizeof(*tlv) + round_up(acl_size, QLINK_ALIGN)); |
|---|
| 2836 | 2608 | tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA); |
|---|
| 2837 | 2609 | tlv->len = cpu_to_le16(acl_size); |
|---|
| 2838 | 2610 | qlink_acl_data_cfg2q(params, (struct qlink_acl_data *)tlv->val); |
|---|
| 2839 | 2611 | |
|---|
| 2840 | 2612 | qtnf_bus_lock(bus); |
|---|
| 2841 | | - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); |
|---|
| 2613 | + ret = qtnf_cmd_send(bus, cmd_skb); |
|---|
| 2614 | + if (ret) |
|---|
| 2615 | + goto out; |
|---|
| 2616 | + |
|---|
| 2617 | +out: |
|---|
| 2842 | 2618 | qtnf_bus_unlock(bus); |
|---|
| 2843 | | - |
|---|
| 2844 | | - if (unlikely(ret)) |
|---|
| 2845 | | - return ret; |
|---|
| 2846 | | - |
|---|
| 2847 | | - switch (res_code) { |
|---|
| 2848 | | - case QLINK_CMD_RESULT_OK: |
|---|
| 2849 | | - break; |
|---|
| 2850 | | - case QLINK_CMD_RESULT_INVALID: |
|---|
| 2851 | | - ret = -EINVAL; |
|---|
| 2852 | | - break; |
|---|
| 2853 | | - default: |
|---|
| 2854 | | - ret = -EOPNOTSUPP; |
|---|
| 2855 | | - break; |
|---|
| 2856 | | - } |
|---|
| 2857 | 2619 | |
|---|
| 2858 | 2620 | return ret; |
|---|
| 2859 | 2621 | } |
|---|
| .. | .. |
|---|
| 2862 | 2624 | { |
|---|
| 2863 | 2625 | struct qtnf_bus *bus = vif->mac->bus; |
|---|
| 2864 | 2626 | struct sk_buff *cmd_skb; |
|---|
| 2865 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2866 | 2627 | struct qlink_cmd_pm_set *cmd; |
|---|
| 2867 | 2628 | int ret = 0; |
|---|
| 2868 | 2629 | |
|---|
| .. | .. |
|---|
| 2877 | 2638 | |
|---|
| 2878 | 2639 | qtnf_bus_lock(bus); |
|---|
| 2879 | 2640 | |
|---|
| 2880 | | - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); |
|---|
| 2881 | | - |
|---|
| 2882 | | - if (unlikely(ret)) |
|---|
| 2641 | + ret = qtnf_cmd_send(bus, cmd_skb); |
|---|
| 2642 | + if (ret) |
|---|
| 2883 | 2643 | goto out; |
|---|
| 2884 | | - |
|---|
| 2885 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2886 | | - pr_err("cmd exec failed: 0x%.4X\n", res_code); |
|---|
| 2887 | | - ret = -EFAULT; |
|---|
| 2888 | | - } |
|---|
| 2889 | 2644 | |
|---|
| 2890 | 2645 | out: |
|---|
| 2891 | 2646 | qtnf_bus_unlock(bus); |
|---|
| 2647 | + |
|---|
| 2648 | + return ret; |
|---|
| 2649 | +} |
|---|
| 2650 | + |
|---|
| 2651 | +int qtnf_cmd_get_tx_power(const struct qtnf_vif *vif, int *dbm) |
|---|
| 2652 | +{ |
|---|
| 2653 | + struct qtnf_bus *bus = vif->mac->bus; |
|---|
| 2654 | + const struct qlink_resp_txpwr *resp; |
|---|
| 2655 | + struct sk_buff *resp_skb = NULL; |
|---|
| 2656 | + struct qlink_cmd_txpwr *cmd; |
|---|
| 2657 | + struct sk_buff *cmd_skb; |
|---|
| 2658 | + int ret = 0; |
|---|
| 2659 | + |
|---|
| 2660 | + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| 2661 | + QLINK_CMD_TXPWR, sizeof(*cmd)); |
|---|
| 2662 | + if (!cmd_skb) |
|---|
| 2663 | + return -ENOMEM; |
|---|
| 2664 | + |
|---|
| 2665 | + cmd = (struct qlink_cmd_txpwr *)cmd_skb->data; |
|---|
| 2666 | + cmd->op_type = QLINK_TXPWR_GET; |
|---|
| 2667 | + |
|---|
| 2668 | + qtnf_bus_lock(bus); |
|---|
| 2669 | + |
|---|
| 2670 | + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, |
|---|
| 2671 | + sizeof(*resp), NULL); |
|---|
| 2672 | + if (ret) |
|---|
| 2673 | + goto out; |
|---|
| 2674 | + |
|---|
| 2675 | + resp = (const struct qlink_resp_txpwr *)resp_skb->data; |
|---|
| 2676 | + *dbm = MBM_TO_DBM(le32_to_cpu(resp->txpwr)); |
|---|
| 2677 | + |
|---|
| 2678 | +out: |
|---|
| 2679 | + qtnf_bus_unlock(bus); |
|---|
| 2680 | + consume_skb(resp_skb); |
|---|
| 2681 | + |
|---|
| 2682 | + return ret; |
|---|
| 2683 | +} |
|---|
| 2684 | + |
|---|
| 2685 | +int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif, |
|---|
| 2686 | + enum nl80211_tx_power_setting type, int mbm) |
|---|
| 2687 | +{ |
|---|
| 2688 | + struct qtnf_bus *bus = vif->mac->bus; |
|---|
| 2689 | + const struct qlink_resp_txpwr *resp; |
|---|
| 2690 | + struct sk_buff *resp_skb = NULL; |
|---|
| 2691 | + struct qlink_cmd_txpwr *cmd; |
|---|
| 2692 | + struct sk_buff *cmd_skb; |
|---|
| 2693 | + int ret = 0; |
|---|
| 2694 | + |
|---|
| 2695 | + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| 2696 | + QLINK_CMD_TXPWR, sizeof(*cmd)); |
|---|
| 2697 | + if (!cmd_skb) |
|---|
| 2698 | + return -ENOMEM; |
|---|
| 2699 | + |
|---|
| 2700 | + cmd = (struct qlink_cmd_txpwr *)cmd_skb->data; |
|---|
| 2701 | + cmd->op_type = QLINK_TXPWR_SET; |
|---|
| 2702 | + cmd->txpwr_setting = type; |
|---|
| 2703 | + cmd->txpwr = cpu_to_le32(mbm); |
|---|
| 2704 | + |
|---|
| 2705 | + qtnf_bus_lock(bus); |
|---|
| 2706 | + |
|---|
| 2707 | + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, |
|---|
| 2708 | + sizeof(*resp), NULL); |
|---|
| 2709 | + |
|---|
| 2710 | + qtnf_bus_unlock(bus); |
|---|
| 2711 | + consume_skb(resp_skb); |
|---|
| 2712 | + |
|---|
| 2892 | 2713 | return ret; |
|---|
| 2893 | 2714 | } |
|---|
| 2894 | 2715 | |
|---|
| .. | .. |
|---|
| 2897 | 2718 | { |
|---|
| 2898 | 2719 | struct qtnf_bus *bus = vif->mac->bus; |
|---|
| 2899 | 2720 | struct sk_buff *cmd_skb; |
|---|
| 2900 | | - u16 res_code = QLINK_CMD_RESULT_OK; |
|---|
| 2901 | 2721 | struct qlink_cmd_wowlan_set *cmd; |
|---|
| 2902 | 2722 | u32 triggers = 0; |
|---|
| 2903 | 2723 | int count = 0; |
|---|
| .. | .. |
|---|
| 2933 | 2753 | |
|---|
| 2934 | 2754 | cmd->triggers = cpu_to_le32(triggers); |
|---|
| 2935 | 2755 | |
|---|
| 2936 | | - ret = qtnf_cmd_send(bus, cmd_skb, &res_code); |
|---|
| 2937 | | - |
|---|
| 2938 | | - if (unlikely(ret)) |
|---|
| 2756 | + ret = qtnf_cmd_send(bus, cmd_skb); |
|---|
| 2757 | + if (ret) |
|---|
| 2939 | 2758 | goto out; |
|---|
| 2940 | | - |
|---|
| 2941 | | - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { |
|---|
| 2942 | | - pr_err("cmd exec failed: 0x%.4X\n", res_code); |
|---|
| 2943 | | - ret = -EFAULT; |
|---|
| 2944 | | - } |
|---|
| 2945 | 2759 | |
|---|
| 2946 | 2760 | out: |
|---|
| 2947 | 2761 | qtnf_bus_unlock(bus); |
|---|
| 2948 | 2762 | return ret; |
|---|
| 2949 | 2763 | } |
|---|
| 2764 | + |
|---|
| 2765 | +int qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain) |
|---|
| 2766 | +{ |
|---|
| 2767 | + struct qtnf_bus *bus = vif->mac->bus; |
|---|
| 2768 | + struct sk_buff *cmd_skb; |
|---|
| 2769 | + struct qlink_cmd_ndev_changeupper *cmd; |
|---|
| 2770 | + int ret; |
|---|
| 2771 | + |
|---|
| 2772 | + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| 2773 | + QLINK_CMD_NDEV_EVENT, |
|---|
| 2774 | + sizeof(*cmd)); |
|---|
| 2775 | + if (!cmd_skb) |
|---|
| 2776 | + return -ENOMEM; |
|---|
| 2777 | + |
|---|
| 2778 | + pr_debug("[VIF%u.%u] set broadcast domain to %d\n", |
|---|
| 2779 | + vif->mac->macid, vif->vifid, br_domain); |
|---|
| 2780 | + |
|---|
| 2781 | + cmd = (struct qlink_cmd_ndev_changeupper *)cmd_skb->data; |
|---|
| 2782 | + cmd->nehdr.event = cpu_to_le16(QLINK_NDEV_EVENT_CHANGEUPPER); |
|---|
| 2783 | + cmd->upper_type = QLINK_NDEV_UPPER_TYPE_BRIDGE; |
|---|
| 2784 | + cmd->br_domain = cpu_to_le32(br_domain); |
|---|
| 2785 | + |
|---|
| 2786 | + qtnf_bus_lock(bus); |
|---|
| 2787 | + ret = qtnf_cmd_send(bus, cmd_skb); |
|---|
| 2788 | + qtnf_bus_unlock(bus); |
|---|
| 2789 | + |
|---|
| 2790 | + if (ret) |
|---|
| 2791 | + pr_err("[VIF%u.%u] failed to set broadcast domain\n", |
|---|
| 2792 | + vif->mac->macid, vif->vifid); |
|---|
| 2793 | + |
|---|
| 2794 | + return ret; |
|---|
| 2795 | +} |
|---|
| 2796 | + |
|---|
| 2797 | +int qtnf_cmd_send_update_owe(struct qtnf_vif *vif, |
|---|
| 2798 | + struct cfg80211_update_owe_info *owe) |
|---|
| 2799 | +{ |
|---|
| 2800 | + struct qlink_cmd_update_owe *cmd; |
|---|
| 2801 | + struct sk_buff *cmd_skb; |
|---|
| 2802 | + int ret; |
|---|
| 2803 | + |
|---|
| 2804 | + if (sizeof(*cmd) + owe->ie_len > QTNF_MAX_CMD_BUF_SIZE) { |
|---|
| 2805 | + pr_warn("VIF%u.%u: OWE update IEs too big: %zu\n", |
|---|
| 2806 | + vif->mac->macid, vif->vifid, owe->ie_len); |
|---|
| 2807 | + return -E2BIG; |
|---|
| 2808 | + } |
|---|
| 2809 | + |
|---|
| 2810 | + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, |
|---|
| 2811 | + QLINK_CMD_UPDATE_OWE, |
|---|
| 2812 | + sizeof(*cmd)); |
|---|
| 2813 | + if (!cmd_skb) |
|---|
| 2814 | + return -ENOMEM; |
|---|
| 2815 | + |
|---|
| 2816 | + cmd = (struct qlink_cmd_update_owe *)cmd_skb->data; |
|---|
| 2817 | + ether_addr_copy(cmd->peer, owe->peer); |
|---|
| 2818 | + cmd->status = cpu_to_le16(owe->status); |
|---|
| 2819 | + if (owe->ie_len && owe->ie) |
|---|
| 2820 | + qtnf_cmd_skb_put_buffer(cmd_skb, owe->ie, owe->ie_len); |
|---|
| 2821 | + |
|---|
| 2822 | + qtnf_bus_lock(vif->mac->bus); |
|---|
| 2823 | + ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); |
|---|
| 2824 | + if (ret) |
|---|
| 2825 | + goto out; |
|---|
| 2826 | + |
|---|
| 2827 | +out: |
|---|
| 2828 | + qtnf_bus_unlock(vif->mac->bus); |
|---|
| 2829 | + |
|---|
| 2830 | + return ret; |
|---|
| 2831 | +} |
|---|