18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/types.h> 58c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "cfg80211.h" 88c2ecf20Sopenharmony_ci#include "core.h" 98c2ecf20Sopenharmony_ci#include "qlink.h" 108c2ecf20Sopenharmony_ci#include "qlink_util.h" 118c2ecf20Sopenharmony_ci#include "bus.h" 128c2ecf20Sopenharmony_ci#include "commands.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* Let device itself to select best values for current conditions */ 158c2ecf20Sopenharmony_ci#define QTNF_SCAN_TIME_AUTO 0 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define QTNF_SCAN_DWELL_ACTIVE_DEFAULT 90 188c2ecf20Sopenharmony_ci#define QTNF_SCAN_DWELL_PASSIVE_DEFAULT 100 198c2ecf20Sopenharmony_ci#define QTNF_SCAN_SAMPLE_DURATION_DEFAULT QTNF_SCAN_TIME_AUTO 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int qtnf_cmd_check_reply_header(const struct qlink_resp *resp, 228c2ecf20Sopenharmony_ci u16 cmd_id, u8 mac_id, u8 vif_id, 238c2ecf20Sopenharmony_ci size_t resp_size) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci if (unlikely(le16_to_cpu(resp->cmd_id) != cmd_id)) { 268c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u CMD%x: bad cmd_id in response: 0x%.4X\n", 278c2ecf20Sopenharmony_ci mac_id, vif_id, cmd_id, le16_to_cpu(resp->cmd_id)); 288c2ecf20Sopenharmony_ci return -EINVAL; 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (unlikely(resp->macid != mac_id)) { 328c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u CMD%x: bad MAC in response: %u\n", 338c2ecf20Sopenharmony_ci mac_id, vif_id, cmd_id, resp->macid); 348c2ecf20Sopenharmony_ci return -EINVAL; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci if (unlikely(resp->vifid != vif_id)) { 388c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u CMD%x: bad VIF in response: %u\n", 398c2ecf20Sopenharmony_ci mac_id, vif_id, cmd_id, resp->vifid); 408c2ecf20Sopenharmony_ci return -EINVAL; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (unlikely(le16_to_cpu(resp->mhdr.len) < resp_size)) { 448c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u CMD%x: bad response size %u < %zu\n", 458c2ecf20Sopenharmony_ci mac_id, vif_id, cmd_id, 468c2ecf20Sopenharmony_ci le16_to_cpu(resp->mhdr.len), resp_size); 478c2ecf20Sopenharmony_ci return -ENOSPC; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int qtnf_cmd_resp_result_decode(enum qlink_cmd_result qcode) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci switch (qcode) { 568c2ecf20Sopenharmony_ci case QLINK_CMD_RESULT_OK: 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci case QLINK_CMD_RESULT_INVALID: 598c2ecf20Sopenharmony_ci return -EINVAL; 608c2ecf20Sopenharmony_ci case QLINK_CMD_RESULT_ENOTSUPP: 618c2ecf20Sopenharmony_ci return -ENOTSUPP; 628c2ecf20Sopenharmony_ci case QLINK_CMD_RESULT_ENOTFOUND: 638c2ecf20Sopenharmony_ci return -ENOENT; 648c2ecf20Sopenharmony_ci case QLINK_CMD_RESULT_EALREADY: 658c2ecf20Sopenharmony_ci return -EALREADY; 668c2ecf20Sopenharmony_ci case QLINK_CMD_RESULT_EADDRINUSE: 678c2ecf20Sopenharmony_ci return -EADDRINUSE; 688c2ecf20Sopenharmony_ci case QLINK_CMD_RESULT_EADDRNOTAVAIL: 698c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 708c2ecf20Sopenharmony_ci case QLINK_CMD_RESULT_EBUSY: 718c2ecf20Sopenharmony_ci return -EBUSY; 728c2ecf20Sopenharmony_ci default: 738c2ecf20Sopenharmony_ci return -EFAULT; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, 788c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb, 798c2ecf20Sopenharmony_ci struct sk_buff **response_skb, 808c2ecf20Sopenharmony_ci size_t const_resp_size, 818c2ecf20Sopenharmony_ci size_t *var_resp_size) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct qlink_cmd *cmd; 848c2ecf20Sopenharmony_ci struct qlink_resp *resp = NULL; 858c2ecf20Sopenharmony_ci struct sk_buff *resp_skb = NULL; 868c2ecf20Sopenharmony_ci int resp_res = 0; 878c2ecf20Sopenharmony_ci u16 cmd_id; 888c2ecf20Sopenharmony_ci u8 mac_id; 898c2ecf20Sopenharmony_ci u8 vif_id; 908c2ecf20Sopenharmony_ci int ret; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd *)cmd_skb->data; 938c2ecf20Sopenharmony_ci cmd_id = le16_to_cpu(cmd->cmd_id); 948c2ecf20Sopenharmony_ci mac_id = cmd->macid; 958c2ecf20Sopenharmony_ci vif_id = cmd->vifid; 968c2ecf20Sopenharmony_ci cmd->mhdr.len = cpu_to_le16(cmd_skb->len); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, cmd_id); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (!qtnf_fw_is_up(bus) && cmd_id != QLINK_CMD_FW_INIT) { 1018c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n", 1028c2ecf20Sopenharmony_ci mac_id, vif_id, cmd_id, bus->fw_state); 1038c2ecf20Sopenharmony_ci dev_kfree_skb(cmd_skb); 1048c2ecf20Sopenharmony_ci return -ENODEV; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb); 1088c2ecf20Sopenharmony_ci if (ret) 1098c2ecf20Sopenharmony_ci goto out; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (WARN_ON(!resp_skb || !resp_skb->data)) { 1128c2ecf20Sopenharmony_ci ret = -EFAULT; 1138c2ecf20Sopenharmony_ci goto out; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci resp = (struct qlink_resp *)resp_skb->data; 1178c2ecf20Sopenharmony_ci resp_res = le16_to_cpu(resp->result); 1188c2ecf20Sopenharmony_ci ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id, 1198c2ecf20Sopenharmony_ci const_resp_size); 1208c2ecf20Sopenharmony_ci if (ret) 1218c2ecf20Sopenharmony_ci goto out; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* Return length of variable part of response */ 1248c2ecf20Sopenharmony_ci if (response_skb && var_resp_size) 1258c2ecf20Sopenharmony_ci *var_resp_size = le16_to_cpu(resp->mhdr.len) - const_resp_size; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciout: 1288c2ecf20Sopenharmony_ci if (response_skb) 1298c2ecf20Sopenharmony_ci *response_skb = resp_skb; 1308c2ecf20Sopenharmony_ci else 1318c2ecf20Sopenharmony_ci consume_skb(resp_skb); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (!ret) 1348c2ecf20Sopenharmony_ci return qtnf_cmd_resp_result_decode(resp_res); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: cmd 0x%.4X failed: %d\n", 1378c2ecf20Sopenharmony_ci mac_id, vif_id, cmd_id, ret); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return ret; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic inline int qtnf_cmd_send(struct qtnf_bus *bus, struct sk_buff *cmd_skb) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, 1458c2ecf20Sopenharmony_ci sizeof(struct qlink_resp), NULL); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic struct sk_buff *qtnf_cmd_alloc_new_cmdskb(u8 macid, u8 vifid, u16 cmd_no, 1498c2ecf20Sopenharmony_ci size_t cmd_size) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct qlink_cmd *cmd; 1528c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci cmd_skb = __dev_alloc_skb(sizeof(*cmd) + 1558c2ecf20Sopenharmony_ci QTNF_MAX_CMD_BUF_SIZE, GFP_KERNEL); 1568c2ecf20Sopenharmony_ci if (unlikely(!cmd_skb)) { 1578c2ecf20Sopenharmony_ci pr_err("VIF%u.%u CMD %u: alloc failed\n", macid, vifid, cmd_no); 1588c2ecf20Sopenharmony_ci return NULL; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci skb_put_zero(cmd_skb, cmd_size); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd *)cmd_skb->data; 1648c2ecf20Sopenharmony_ci cmd->mhdr.len = cpu_to_le16(cmd_skb->len); 1658c2ecf20Sopenharmony_ci cmd->mhdr.type = cpu_to_le16(QLINK_MSG_TYPE_CMD); 1668c2ecf20Sopenharmony_ci cmd->cmd_id = cpu_to_le16(cmd_no); 1678c2ecf20Sopenharmony_ci cmd->macid = macid; 1688c2ecf20Sopenharmony_ci cmd->vifid = vifid; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return cmd_skb; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void qtnf_cmd_tlv_ie_set_add(struct sk_buff *cmd_skb, u8 frame_type, 1748c2ecf20Sopenharmony_ci const u8 *buf, size_t len) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct qlink_tlv_ie_set *tlv; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci tlv = (struct qlink_tlv_ie_set *)skb_put(cmd_skb, sizeof(*tlv) + 1798c2ecf20Sopenharmony_ci round_up(len, QLINK_ALIGN)); 1808c2ecf20Sopenharmony_ci tlv->hdr.type = cpu_to_le16(QTN_TLV_ID_IE_SET); 1818c2ecf20Sopenharmony_ci tlv->hdr.len = cpu_to_le16(len + sizeof(*tlv) - sizeof(tlv->hdr)); 1828c2ecf20Sopenharmony_ci tlv->type = frame_type; 1838c2ecf20Sopenharmony_ci tlv->flags = 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (len && buf) 1868c2ecf20Sopenharmony_ci memcpy(tlv->ie_data, buf, len); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif, 1908c2ecf20Sopenharmony_ci const struct cfg80211_ap_settings *s) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci unsigned int len = sizeof(struct qlink_cmd_start_ap); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci len += round_up(s->ssid_len, QLINK_ALIGN); 1958c2ecf20Sopenharmony_ci len += round_up(s->beacon.head_len, QLINK_ALIGN); 1968c2ecf20Sopenharmony_ci len += round_up(s->beacon.tail_len, QLINK_ALIGN); 1978c2ecf20Sopenharmony_ci len += round_up(s->beacon.beacon_ies_len, QLINK_ALIGN); 1988c2ecf20Sopenharmony_ci len += round_up(s->beacon.proberesp_ies_len, QLINK_ALIGN); 1998c2ecf20Sopenharmony_ci len += round_up(s->beacon.assocresp_ies_len, QLINK_ALIGN); 2008c2ecf20Sopenharmony_ci len += round_up(s->beacon.probe_resp_len, QLINK_ALIGN); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (cfg80211_chandef_valid(&s->chandef)) 2038c2ecf20Sopenharmony_ci len += sizeof(struct qlink_tlv_chandef); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (s->acl) { 2068c2ecf20Sopenharmony_ci unsigned int acl_len = struct_size(s->acl, mac_addrs, 2078c2ecf20Sopenharmony_ci s->acl->n_acl_entries); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci len += sizeof(struct qlink_tlv_hdr) + 2108c2ecf20Sopenharmony_ci round_up(acl_len, QLINK_ALIGN); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) { 2148c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: can not fit AP settings: %u\n", 2158c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, len); 2168c2ecf20Sopenharmony_ci return false; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return true; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void qtnf_cmd_tlv_ie_ext_add(struct sk_buff *cmd_skb, u8 eid_ext, 2238c2ecf20Sopenharmony_ci const void *buf, size_t len) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct qlink_tlv_ext_ie *tlv; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci tlv = (struct qlink_tlv_ext_ie *)skb_put(cmd_skb, sizeof(*tlv) + len); 2288c2ecf20Sopenharmony_ci tlv->hdr.type = cpu_to_le16(WLAN_EID_EXTENSION); 2298c2ecf20Sopenharmony_ci tlv->hdr.len = cpu_to_le16(sizeof(*tlv) + len - sizeof(tlv->hdr)); 2308c2ecf20Sopenharmony_ci tlv->eid_ext = eid_ext; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (len && buf) 2338c2ecf20Sopenharmony_ci memcpy(tlv->ie_data, buf, len); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ciint qtnf_cmd_send_start_ap(struct qtnf_vif *vif, 2378c2ecf20Sopenharmony_ci const struct cfg80211_ap_settings *s) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 2408c2ecf20Sopenharmony_ci struct qlink_cmd_start_ap *cmd; 2418c2ecf20Sopenharmony_ci struct qlink_auth_encr *aen; 2428c2ecf20Sopenharmony_ci int ret; 2438c2ecf20Sopenharmony_ci int i; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (!qtnf_cmd_start_ap_can_fit(vif, s)) 2468c2ecf20Sopenharmony_ci return -E2BIG; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 2498c2ecf20Sopenharmony_ci QLINK_CMD_START_AP, 2508c2ecf20Sopenharmony_ci sizeof(*cmd)); 2518c2ecf20Sopenharmony_ci if (!cmd_skb) 2528c2ecf20Sopenharmony_ci return -ENOMEM; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_start_ap *)cmd_skb->data; 2558c2ecf20Sopenharmony_ci cmd->dtim_period = s->dtim_period; 2568c2ecf20Sopenharmony_ci cmd->beacon_interval = cpu_to_le16(s->beacon_interval); 2578c2ecf20Sopenharmony_ci cmd->hidden_ssid = qlink_hidden_ssid_nl2q(s->hidden_ssid); 2588c2ecf20Sopenharmony_ci cmd->inactivity_timeout = cpu_to_le16(s->inactivity_timeout); 2598c2ecf20Sopenharmony_ci cmd->smps_mode = s->smps_mode; 2608c2ecf20Sopenharmony_ci cmd->p2p_ctwindow = s->p2p_ctwindow; 2618c2ecf20Sopenharmony_ci cmd->p2p_opp_ps = s->p2p_opp_ps; 2628c2ecf20Sopenharmony_ci cmd->pbss = s->pbss; 2638c2ecf20Sopenharmony_ci cmd->ht_required = s->ht_required; 2648c2ecf20Sopenharmony_ci cmd->vht_required = s->vht_required; 2658c2ecf20Sopenharmony_ci cmd->twt_responder = s->twt_responder; 2668c2ecf20Sopenharmony_ci if (s->he_obss_pd.enable) { 2678c2ecf20Sopenharmony_ci cmd->sr_params.sr_control |= QLINK_SR_SRG_INFORMATION_PRESENT; 2688c2ecf20Sopenharmony_ci cmd->sr_params.srg_obss_pd_min_offset = 2698c2ecf20Sopenharmony_ci s->he_obss_pd.min_offset; 2708c2ecf20Sopenharmony_ci cmd->sr_params.srg_obss_pd_max_offset = 2718c2ecf20Sopenharmony_ci s->he_obss_pd.max_offset; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci aen = &cmd->aen; 2758c2ecf20Sopenharmony_ci aen->auth_type = s->auth_type; 2768c2ecf20Sopenharmony_ci aen->privacy = !!s->privacy; 2778c2ecf20Sopenharmony_ci aen->wpa_versions = cpu_to_le32(s->crypto.wpa_versions); 2788c2ecf20Sopenharmony_ci aen->cipher_group = cpu_to_le32(s->crypto.cipher_group); 2798c2ecf20Sopenharmony_ci aen->n_ciphers_pairwise = cpu_to_le32(s->crypto.n_ciphers_pairwise); 2808c2ecf20Sopenharmony_ci for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) 2818c2ecf20Sopenharmony_ci aen->ciphers_pairwise[i] = 2828c2ecf20Sopenharmony_ci cpu_to_le32(s->crypto.ciphers_pairwise[i]); 2838c2ecf20Sopenharmony_ci aen->n_akm_suites = cpu_to_le32(s->crypto.n_akm_suites); 2848c2ecf20Sopenharmony_ci for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) 2858c2ecf20Sopenharmony_ci aen->akm_suites[i] = cpu_to_le32(s->crypto.akm_suites[i]); 2868c2ecf20Sopenharmony_ci aen->control_port = s->crypto.control_port; 2878c2ecf20Sopenharmony_ci aen->control_port_no_encrypt = s->crypto.control_port_no_encrypt; 2888c2ecf20Sopenharmony_ci aen->control_port_ethertype = 2898c2ecf20Sopenharmony_ci cpu_to_le16(be16_to_cpu(s->crypto.control_port_ethertype)); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (s->ssid && s->ssid_len > 0 && s->ssid_len <= IEEE80211_MAX_SSID_LEN) 2928c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, s->ssid, 2938c2ecf20Sopenharmony_ci s->ssid_len); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (cfg80211_chandef_valid(&s->chandef)) { 2968c2ecf20Sopenharmony_ci struct qlink_tlv_chandef *chtlv = 2978c2ecf20Sopenharmony_ci (struct qlink_tlv_chandef *)skb_put(cmd_skb, 2988c2ecf20Sopenharmony_ci sizeof(*chtlv)); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci chtlv->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANDEF); 3018c2ecf20Sopenharmony_ci chtlv->hdr.len = cpu_to_le16(sizeof(*chtlv) - 3028c2ecf20Sopenharmony_ci sizeof(chtlv->hdr)); 3038c2ecf20Sopenharmony_ci qlink_chandef_cfg2q(&s->chandef, &chtlv->chdef); 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_BEACON_HEAD, 3078c2ecf20Sopenharmony_ci s->beacon.head, s->beacon.head_len); 3088c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_BEACON_TAIL, 3098c2ecf20Sopenharmony_ci s->beacon.tail, s->beacon.tail_len); 3108c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_BEACON_IES, 3118c2ecf20Sopenharmony_ci s->beacon.beacon_ies, s->beacon.beacon_ies_len); 3128c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_PROBE_RESP, 3138c2ecf20Sopenharmony_ci s->beacon.probe_resp, s->beacon.probe_resp_len); 3148c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_PROBE_RESP_IES, 3158c2ecf20Sopenharmony_ci s->beacon.proberesp_ies, 3168c2ecf20Sopenharmony_ci s->beacon.proberesp_ies_len); 3178c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_ASSOC_RESP, 3188c2ecf20Sopenharmony_ci s->beacon.assocresp_ies, 3198c2ecf20Sopenharmony_ci s->beacon.assocresp_ies_len); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (s->ht_cap) { 3228c2ecf20Sopenharmony_ci struct qlink_tlv_hdr *tlv = (struct qlink_tlv_hdr *) 3238c2ecf20Sopenharmony_ci skb_put(cmd_skb, sizeof(*tlv) + 3248c2ecf20Sopenharmony_ci round_up(sizeof(*s->ht_cap), QLINK_ALIGN)); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci tlv->type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 3278c2ecf20Sopenharmony_ci tlv->len = cpu_to_le16(sizeof(*s->ht_cap)); 3288c2ecf20Sopenharmony_ci memcpy(tlv->val, s->ht_cap, sizeof(*s->ht_cap)); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (s->vht_cap) { 3328c2ecf20Sopenharmony_ci struct qlink_tlv_hdr *tlv = (struct qlink_tlv_hdr *) 3338c2ecf20Sopenharmony_ci skb_put(cmd_skb, sizeof(*tlv) + sizeof(*s->vht_cap)); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci tlv->type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY); 3368c2ecf20Sopenharmony_ci tlv->len = cpu_to_le16(sizeof(*s->vht_cap)); 3378c2ecf20Sopenharmony_ci memcpy(tlv->val, s->vht_cap, sizeof(*s->vht_cap)); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (s->he_cap) 3418c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_ext_add(cmd_skb, WLAN_EID_EXT_HE_CAPABILITY, 3428c2ecf20Sopenharmony_ci s->he_cap, sizeof(*s->he_cap)); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (s->acl) { 3458c2ecf20Sopenharmony_ci size_t acl_size = struct_size(s->acl, mac_addrs, 3468c2ecf20Sopenharmony_ci s->acl->n_acl_entries); 3478c2ecf20Sopenharmony_ci struct qlink_tlv_hdr *tlv = 3488c2ecf20Sopenharmony_ci skb_put(cmd_skb, 3498c2ecf20Sopenharmony_ci sizeof(*tlv) + round_up(acl_size, QLINK_ALIGN)); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA); 3528c2ecf20Sopenharmony_ci tlv->len = cpu_to_le16(acl_size); 3538c2ecf20Sopenharmony_ci qlink_acl_data_cfg2q(s->acl, (struct qlink_acl_data *)tlv->val); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 3578c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 3588c2ecf20Sopenharmony_ci if (ret) 3598c2ecf20Sopenharmony_ci goto out; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci netif_carrier_on(vif->netdev); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciout: 3648c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return ret; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ciint qtnf_cmd_send_stop_ap(struct qtnf_vif *vif) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 3728c2ecf20Sopenharmony_ci int ret; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 3758c2ecf20Sopenharmony_ci QLINK_CMD_STOP_AP, 3768c2ecf20Sopenharmony_ci sizeof(struct qlink_cmd)); 3778c2ecf20Sopenharmony_ci if (!cmd_skb) 3788c2ecf20Sopenharmony_ci return -ENOMEM; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 3818c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 3828c2ecf20Sopenharmony_ci if (ret) 3838c2ecf20Sopenharmony_ci goto out; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ciout: 3868c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ciint qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 3948c2ecf20Sopenharmony_ci struct qlink_cmd_mgmt_frame_register *cmd; 3958c2ecf20Sopenharmony_ci int ret; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 3988c2ecf20Sopenharmony_ci QLINK_CMD_REGISTER_MGMT, 3998c2ecf20Sopenharmony_ci sizeof(*cmd)); 4008c2ecf20Sopenharmony_ci if (!cmd_skb) 4018c2ecf20Sopenharmony_ci return -ENOMEM; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_mgmt_frame_register *)cmd_skb->data; 4068c2ecf20Sopenharmony_ci cmd->frame_type = cpu_to_le16(frame_type); 4078c2ecf20Sopenharmony_ci cmd->do_register = reg; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 4108c2ecf20Sopenharmony_ci if (ret) 4118c2ecf20Sopenharmony_ci goto out; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ciout: 4148c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return ret; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ciint qtnf_cmd_send_frame(struct qtnf_vif *vif, u32 cookie, u16 flags, 4208c2ecf20Sopenharmony_ci u16 freq, const u8 *buf, size_t len) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 4238c2ecf20Sopenharmony_ci struct qlink_cmd_frame_tx *cmd; 4248c2ecf20Sopenharmony_ci int ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { 4278c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: frame is too big: %zu\n", vif->mac->macid, 4288c2ecf20Sopenharmony_ci vif->vifid, len); 4298c2ecf20Sopenharmony_ci return -E2BIG; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 4338c2ecf20Sopenharmony_ci QLINK_CMD_SEND_FRAME, 4348c2ecf20Sopenharmony_ci sizeof(*cmd)); 4358c2ecf20Sopenharmony_ci if (!cmd_skb) 4368c2ecf20Sopenharmony_ci return -ENOMEM; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_frame_tx *)cmd_skb->data; 4418c2ecf20Sopenharmony_ci cmd->cookie = cpu_to_le32(cookie); 4428c2ecf20Sopenharmony_ci cmd->freq = cpu_to_le16(freq); 4438c2ecf20Sopenharmony_ci cmd->flags = cpu_to_le16(flags); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (len && buf) 4468c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_buffer(cmd_skb, buf, len); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 4498c2ecf20Sopenharmony_ci if (ret) 4508c2ecf20Sopenharmony_ci goto out; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ciout: 4538c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return ret; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ciint qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type, 4598c2ecf20Sopenharmony_ci const u8 *buf, size_t len) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 4628c2ecf20Sopenharmony_ci int ret; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (len > QTNF_MAX_CMD_BUF_SIZE) { 4658c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: %u frame is too big: %zu\n", vif->mac->macid, 4668c2ecf20Sopenharmony_ci vif->vifid, frame_type, len); 4678c2ecf20Sopenharmony_ci return -E2BIG; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 4718c2ecf20Sopenharmony_ci QLINK_CMD_MGMT_SET_APPIE, 4728c2ecf20Sopenharmony_ci sizeof(struct qlink_cmd)); 4738c2ecf20Sopenharmony_ci if (!cmd_skb) 4748c2ecf20Sopenharmony_ci return -ENOMEM; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 4798c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 4808c2ecf20Sopenharmony_ci if (ret) 4818c2ecf20Sopenharmony_ci goto out; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ciout: 4848c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return ret; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic void 4908c2ecf20Sopenharmony_ciqtnf_sta_info_parse_rate(struct rate_info *rate_dst, 4918c2ecf20Sopenharmony_ci const struct qlink_sta_info_rate *rate_src) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci rate_dst->legacy = get_unaligned_le16(&rate_src->rate) * 10; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci rate_dst->mcs = rate_src->mcs; 4968c2ecf20Sopenharmony_ci rate_dst->nss = rate_src->nss; 4978c2ecf20Sopenharmony_ci rate_dst->flags = 0; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci switch (rate_src->bw) { 5008c2ecf20Sopenharmony_ci case QLINK_CHAN_WIDTH_5: 5018c2ecf20Sopenharmony_ci rate_dst->bw = RATE_INFO_BW_5; 5028c2ecf20Sopenharmony_ci break; 5038c2ecf20Sopenharmony_ci case QLINK_CHAN_WIDTH_10: 5048c2ecf20Sopenharmony_ci rate_dst->bw = RATE_INFO_BW_10; 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci case QLINK_CHAN_WIDTH_20: 5078c2ecf20Sopenharmony_ci case QLINK_CHAN_WIDTH_20_NOHT: 5088c2ecf20Sopenharmony_ci rate_dst->bw = RATE_INFO_BW_20; 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci case QLINK_CHAN_WIDTH_40: 5118c2ecf20Sopenharmony_ci rate_dst->bw = RATE_INFO_BW_40; 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci case QLINK_CHAN_WIDTH_80: 5148c2ecf20Sopenharmony_ci rate_dst->bw = RATE_INFO_BW_80; 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci case QLINK_CHAN_WIDTH_160: 5178c2ecf20Sopenharmony_ci rate_dst->bw = RATE_INFO_BW_160; 5188c2ecf20Sopenharmony_ci break; 5198c2ecf20Sopenharmony_ci default: 5208c2ecf20Sopenharmony_ci rate_dst->bw = 0; 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_HT_MCS) 5258c2ecf20Sopenharmony_ci rate_dst->flags |= RATE_INFO_FLAGS_MCS; 5268c2ecf20Sopenharmony_ci else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS) 5278c2ecf20Sopenharmony_ci rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS; 5288c2ecf20Sopenharmony_ci else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_HE_MCS) 5298c2ecf20Sopenharmony_ci rate_dst->flags |= RATE_INFO_FLAGS_HE_MCS; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_SHORT_GI) 5328c2ecf20Sopenharmony_ci rate_dst->flags |= RATE_INFO_FLAGS_SHORT_GI; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic void 5368c2ecf20Sopenharmony_ciqtnf_sta_info_parse_flags(struct nl80211_sta_flag_update *dst, 5378c2ecf20Sopenharmony_ci const struct qlink_sta_info_state *src) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci u32 mask, value; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci dst->mask = 0; 5428c2ecf20Sopenharmony_ci dst->set = 0; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci mask = le32_to_cpu(src->mask); 5458c2ecf20Sopenharmony_ci value = le32_to_cpu(src->value); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (mask & QLINK_STA_FLAG_AUTHORIZED) { 5488c2ecf20Sopenharmony_ci dst->mask |= BIT(NL80211_STA_FLAG_AUTHORIZED); 5498c2ecf20Sopenharmony_ci if (value & QLINK_STA_FLAG_AUTHORIZED) 5508c2ecf20Sopenharmony_ci dst->set |= BIT(NL80211_STA_FLAG_AUTHORIZED); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (mask & QLINK_STA_FLAG_SHORT_PREAMBLE) { 5548c2ecf20Sopenharmony_ci dst->mask |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); 5558c2ecf20Sopenharmony_ci if (value & QLINK_STA_FLAG_SHORT_PREAMBLE) 5568c2ecf20Sopenharmony_ci dst->set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (mask & QLINK_STA_FLAG_WME) { 5608c2ecf20Sopenharmony_ci dst->mask |= BIT(NL80211_STA_FLAG_WME); 5618c2ecf20Sopenharmony_ci if (value & QLINK_STA_FLAG_WME) 5628c2ecf20Sopenharmony_ci dst->set |= BIT(NL80211_STA_FLAG_WME); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (mask & QLINK_STA_FLAG_MFP) { 5668c2ecf20Sopenharmony_ci dst->mask |= BIT(NL80211_STA_FLAG_MFP); 5678c2ecf20Sopenharmony_ci if (value & QLINK_STA_FLAG_MFP) 5688c2ecf20Sopenharmony_ci dst->set |= BIT(NL80211_STA_FLAG_MFP); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (mask & QLINK_STA_FLAG_AUTHENTICATED) { 5728c2ecf20Sopenharmony_ci dst->mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED); 5738c2ecf20Sopenharmony_ci if (value & QLINK_STA_FLAG_AUTHENTICATED) 5748c2ecf20Sopenharmony_ci dst->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (mask & QLINK_STA_FLAG_TDLS_PEER) { 5788c2ecf20Sopenharmony_ci dst->mask |= BIT(NL80211_STA_FLAG_TDLS_PEER); 5798c2ecf20Sopenharmony_ci if (value & QLINK_STA_FLAG_TDLS_PEER) 5808c2ecf20Sopenharmony_ci dst->set |= BIT(NL80211_STA_FLAG_TDLS_PEER); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (mask & QLINK_STA_FLAG_ASSOCIATED) { 5848c2ecf20Sopenharmony_ci dst->mask |= BIT(NL80211_STA_FLAG_ASSOCIATED); 5858c2ecf20Sopenharmony_ci if (value & QLINK_STA_FLAG_ASSOCIATED) 5868c2ecf20Sopenharmony_ci dst->set |= BIT(NL80211_STA_FLAG_ASSOCIATED); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic void 5918c2ecf20Sopenharmony_ciqtnf_cmd_sta_info_parse(struct station_info *sinfo, const u8 *data, 5928c2ecf20Sopenharmony_ci size_t resp_size) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci const struct qlink_tlv_hdr *tlv; 5958c2ecf20Sopenharmony_ci const struct qlink_sta_stats *stats = NULL; 5968c2ecf20Sopenharmony_ci const u8 *map = NULL; 5978c2ecf20Sopenharmony_ci unsigned int map_len = 0; 5988c2ecf20Sopenharmony_ci unsigned int stats_len = 0; 5998c2ecf20Sopenharmony_ci u16 tlv_len; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci#define qtnf_sta_stat_avail(stat_name, bitn) \ 6028c2ecf20Sopenharmony_ci (qtnf_utils_is_bit_set(map, bitn, map_len) && \ 6038c2ecf20Sopenharmony_ci (offsetofend(struct qlink_sta_stats, stat_name) <= stats_len)) 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci qlink_for_each_tlv(tlv, data, resp_size) { 6068c2ecf20Sopenharmony_ci tlv_len = le16_to_cpu(tlv->len); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci switch (le16_to_cpu(tlv->type)) { 6098c2ecf20Sopenharmony_ci case QTN_TLV_ID_BITMAP: 6108c2ecf20Sopenharmony_ci map_len = tlv_len; 6118c2ecf20Sopenharmony_ci map = tlv->val; 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci case QTN_TLV_ID_STA_STATS: 6148c2ecf20Sopenharmony_ci stats_len = tlv_len; 6158c2ecf20Sopenharmony_ci stats = (const struct qlink_sta_stats *)tlv->val; 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci default: 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (!qlink_tlv_parsing_ok(tlv, data, resp_size)) { 6238c2ecf20Sopenharmony_ci pr_err("Malformed TLV buffer\n"); 6248c2ecf20Sopenharmony_ci return; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (!map || !stats) 6288c2ecf20Sopenharmony_ci return; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(inactive_time, QLINK_STA_INFO_INACTIVE_TIME)) { 6318c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME); 6328c2ecf20Sopenharmony_ci sinfo->inactive_time = le32_to_cpu(stats->inactive_time); 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(connected_time, 6368c2ecf20Sopenharmony_ci QLINK_STA_INFO_CONNECTED_TIME)) { 6378c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME); 6388c2ecf20Sopenharmony_ci sinfo->connected_time = le32_to_cpu(stats->connected_time); 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(signal, QLINK_STA_INFO_SIGNAL)) { 6428c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); 6438c2ecf20Sopenharmony_ci sinfo->signal = stats->signal - QLINK_RSSI_OFFSET; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(signal_avg, QLINK_STA_INFO_SIGNAL_AVG)) { 6478c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); 6488c2ecf20Sopenharmony_ci sinfo->signal_avg = stats->signal_avg - QLINK_RSSI_OFFSET; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(rxrate, QLINK_STA_INFO_RX_BITRATE)) { 6528c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); 6538c2ecf20Sopenharmony_ci qtnf_sta_info_parse_rate(&sinfo->rxrate, &stats->rxrate); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(txrate, QLINK_STA_INFO_TX_BITRATE)) { 6578c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 6588c2ecf20Sopenharmony_ci qtnf_sta_info_parse_rate(&sinfo->txrate, &stats->txrate); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(sta_flags, QLINK_STA_INFO_STA_FLAGS)) { 6628c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_STA_FLAGS); 6638c2ecf20Sopenharmony_ci qtnf_sta_info_parse_flags(&sinfo->sta_flags, &stats->sta_flags); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES)) { 6678c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES); 6688c2ecf20Sopenharmony_ci sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes); 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES)) { 6728c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES); 6738c2ecf20Sopenharmony_ci sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes); 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES64)) { 6778c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); 6788c2ecf20Sopenharmony_ci sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes); 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES64)) { 6828c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); 6838c2ecf20Sopenharmony_ci sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(rx_packets, QLINK_STA_INFO_RX_PACKETS)) { 6878c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); 6888c2ecf20Sopenharmony_ci sinfo->rx_packets = le32_to_cpu(stats->rx_packets); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(tx_packets, QLINK_STA_INFO_TX_PACKETS)) { 6928c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); 6938c2ecf20Sopenharmony_ci sinfo->tx_packets = le32_to_cpu(stats->tx_packets); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(rx_beacon, QLINK_STA_INFO_BEACON_RX)) { 6978c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX); 6988c2ecf20Sopenharmony_ci sinfo->rx_beacon = le64_to_cpu(stats->rx_beacon); 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(rx_dropped_misc, QLINK_STA_INFO_RX_DROP_MISC)) { 7028c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC); 7038c2ecf20Sopenharmony_ci sinfo->rx_dropped_misc = le32_to_cpu(stats->rx_dropped_misc); 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (qtnf_sta_stat_avail(tx_failed, QLINK_STA_INFO_TX_FAILED)) { 7078c2ecf20Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); 7088c2ecf20Sopenharmony_ci sinfo->tx_failed = le32_to_cpu(stats->tx_failed); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci#undef qtnf_sta_stat_avail 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ciint qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac, 7158c2ecf20Sopenharmony_ci struct station_info *sinfo) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb, *resp_skb = NULL; 7188c2ecf20Sopenharmony_ci struct qlink_cmd_get_sta_info *cmd; 7198c2ecf20Sopenharmony_ci const struct qlink_resp_get_sta_info *resp; 7208c2ecf20Sopenharmony_ci size_t var_resp_len = 0; 7218c2ecf20Sopenharmony_ci int ret = 0; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 7248c2ecf20Sopenharmony_ci QLINK_CMD_GET_STA_INFO, 7258c2ecf20Sopenharmony_ci sizeof(*cmd)); 7268c2ecf20Sopenharmony_ci if (!cmd_skb) 7278c2ecf20Sopenharmony_ci return -ENOMEM; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_get_sta_info *)cmd_skb->data; 7328c2ecf20Sopenharmony_ci ether_addr_copy(cmd->sta_addr, sta_mac); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, 7358c2ecf20Sopenharmony_ci sizeof(*resp), &var_resp_len); 7368c2ecf20Sopenharmony_ci if (ret) 7378c2ecf20Sopenharmony_ci goto out; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci resp = (const struct qlink_resp_get_sta_info *)resp_skb->data; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (!ether_addr_equal(sta_mac, resp->sta_addr)) { 7428c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n", 7438c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac); 7448c2ecf20Sopenharmony_ci ret = -EINVAL; 7458c2ecf20Sopenharmony_ci goto out; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci qtnf_cmd_sta_info_parse(sinfo, resp->info, var_resp_len); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ciout: 7518c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 7528c2ecf20Sopenharmony_ci consume_skb(resp_skb); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci return ret; 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif, 7588c2ecf20Sopenharmony_ci enum nl80211_iftype iftype, 7598c2ecf20Sopenharmony_ci int use4addr, 7608c2ecf20Sopenharmony_ci u8 *mac_addr, 7618c2ecf20Sopenharmony_ci enum qlink_cmd_type cmd_type) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb, *resp_skb = NULL; 7648c2ecf20Sopenharmony_ci struct qlink_cmd_manage_intf *cmd; 7658c2ecf20Sopenharmony_ci const struct qlink_resp_manage_intf *resp; 7668c2ecf20Sopenharmony_ci int ret = 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 7698c2ecf20Sopenharmony_ci cmd_type, 7708c2ecf20Sopenharmony_ci sizeof(*cmd)); 7718c2ecf20Sopenharmony_ci if (!cmd_skb) 7728c2ecf20Sopenharmony_ci return -ENOMEM; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data; 7778c2ecf20Sopenharmony_ci cmd->intf_info.use4addr = use4addr; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci switch (iftype) { 7808c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 7818c2ecf20Sopenharmony_ci cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP); 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 7848c2ecf20Sopenharmony_ci cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION); 7858c2ecf20Sopenharmony_ci break; 7868c2ecf20Sopenharmony_ci default: 7878c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: unsupported type %d\n", vif->mac->macid, 7888c2ecf20Sopenharmony_ci vif->vifid, iftype); 7898c2ecf20Sopenharmony_ci ret = -EINVAL; 7908c2ecf20Sopenharmony_ci goto out; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (mac_addr) 7948c2ecf20Sopenharmony_ci ether_addr_copy(cmd->intf_info.mac_addr, mac_addr); 7958c2ecf20Sopenharmony_ci else 7968c2ecf20Sopenharmony_ci eth_zero_addr(cmd->intf_info.mac_addr); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, 7998c2ecf20Sopenharmony_ci sizeof(*resp), NULL); 8008c2ecf20Sopenharmony_ci if (ret) 8018c2ecf20Sopenharmony_ci goto out; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci resp = (const struct qlink_resp_manage_intf *)resp_skb->data; 8048c2ecf20Sopenharmony_ci ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ciout: 8078c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 8088c2ecf20Sopenharmony_ci consume_skb(resp_skb); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci return ret; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ciint qtnf_cmd_send_add_intf(struct qtnf_vif *vif, enum nl80211_iftype iftype, 8148c2ecf20Sopenharmony_ci int use4addr, u8 *mac_addr) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci return qtnf_cmd_send_add_change_intf(vif, iftype, use4addr, mac_addr, 8178c2ecf20Sopenharmony_ci QLINK_CMD_ADD_INTF); 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ciint qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif, 8218c2ecf20Sopenharmony_ci enum nl80211_iftype iftype, 8228c2ecf20Sopenharmony_ci int use4addr, 8238c2ecf20Sopenharmony_ci u8 *mac_addr) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci int ret; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_add_change_intf(vif, iftype, use4addr, mac_addr, 8288c2ecf20Sopenharmony_ci QLINK_CMD_CHANGE_INTF); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* Regulatory settings may be different for different interface types */ 8318c2ecf20Sopenharmony_ci if (ret == 0 && vif->wdev.iftype != iftype) { 8328c2ecf20Sopenharmony_ci enum nl80211_band band; 8338c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(vif->mac); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; ++band) { 8368c2ecf20Sopenharmony_ci if (!wiphy->bands[band]) 8378c2ecf20Sopenharmony_ci continue; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci qtnf_cmd_band_info_get(vif->mac, wiphy->bands[band]); 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return ret; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ciint qtnf_cmd_send_del_intf(struct qtnf_vif *vif) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 8498c2ecf20Sopenharmony_ci struct qlink_cmd_manage_intf *cmd; 8508c2ecf20Sopenharmony_ci int ret = 0; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 8538c2ecf20Sopenharmony_ci QLINK_CMD_DEL_INTF, 8548c2ecf20Sopenharmony_ci sizeof(*cmd)); 8558c2ecf20Sopenharmony_ci if (!cmd_skb) 8568c2ecf20Sopenharmony_ci return -ENOMEM; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci switch (vif->wdev.iftype) { 8638c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 8648c2ecf20Sopenharmony_ci cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP); 8658c2ecf20Sopenharmony_ci break; 8668c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 8678c2ecf20Sopenharmony_ci cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION); 8688c2ecf20Sopenharmony_ci break; 8698c2ecf20Sopenharmony_ci default: 8708c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: unsupported iftype %d\n", vif->mac->macid, 8718c2ecf20Sopenharmony_ci vif->vifid, vif->wdev.iftype); 8728c2ecf20Sopenharmony_ci dev_kfree_skb(cmd_skb); 8738c2ecf20Sopenharmony_ci ret = -EINVAL; 8748c2ecf20Sopenharmony_ci goto out; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci eth_zero_addr(cmd->intf_info.mac_addr); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 8808c2ecf20Sopenharmony_ci if (ret) 8818c2ecf20Sopenharmony_ci goto out; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ciout: 8848c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 8858c2ecf20Sopenharmony_ci return ret; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic int 8898c2ecf20Sopenharmony_ciqtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, 8908c2ecf20Sopenharmony_ci const struct qlink_resp_get_hw_info *resp, 8918c2ecf20Sopenharmony_ci size_t info_len) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct qtnf_hw_info *hwinfo = &bus->hw_info; 8948c2ecf20Sopenharmony_ci const struct qlink_tlv_hdr *tlv; 8958c2ecf20Sopenharmony_ci const char *bld_name = NULL; 8968c2ecf20Sopenharmony_ci const char *bld_rev = NULL; 8978c2ecf20Sopenharmony_ci const char *bld_type = NULL; 8988c2ecf20Sopenharmony_ci const char *bld_label = NULL; 8998c2ecf20Sopenharmony_ci u32 bld_tmstamp = 0; 9008c2ecf20Sopenharmony_ci u32 plat_id = 0; 9018c2ecf20Sopenharmony_ci const char *hw_id = NULL; 9028c2ecf20Sopenharmony_ci const char *calibration_ver = NULL; 9038c2ecf20Sopenharmony_ci const char *uboot_ver = NULL; 9048c2ecf20Sopenharmony_ci u32 hw_ver = 0; 9058c2ecf20Sopenharmony_ci u16 tlv_type; 9068c2ecf20Sopenharmony_ci u16 tlv_len; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci hwinfo->num_mac = resp->num_mac; 9098c2ecf20Sopenharmony_ci hwinfo->mac_bitmap = resp->mac_bitmap; 9108c2ecf20Sopenharmony_ci hwinfo->fw_ver = le32_to_cpu(resp->fw_ver); 9118c2ecf20Sopenharmony_ci hwinfo->total_tx_chain = resp->total_tx_chain; 9128c2ecf20Sopenharmony_ci hwinfo->total_rx_chain = resp->total_rx_chain; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci bld_tmstamp = le32_to_cpu(resp->bld_tmstamp); 9158c2ecf20Sopenharmony_ci plat_id = le32_to_cpu(resp->plat_id); 9168c2ecf20Sopenharmony_ci hw_ver = le32_to_cpu(resp->hw_ver); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci qlink_for_each_tlv(tlv, resp->info, info_len) { 9198c2ecf20Sopenharmony_ci tlv_type = le16_to_cpu(tlv->type); 9208c2ecf20Sopenharmony_ci tlv_len = le16_to_cpu(tlv->len); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci switch (tlv_type) { 9238c2ecf20Sopenharmony_ci case QTN_TLV_ID_BUILD_NAME: 9248c2ecf20Sopenharmony_ci bld_name = (const void *)tlv->val; 9258c2ecf20Sopenharmony_ci break; 9268c2ecf20Sopenharmony_ci case QTN_TLV_ID_BUILD_REV: 9278c2ecf20Sopenharmony_ci bld_rev = (const void *)tlv->val; 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci case QTN_TLV_ID_BUILD_TYPE: 9308c2ecf20Sopenharmony_ci bld_type = (const void *)tlv->val; 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci case QTN_TLV_ID_BUILD_LABEL: 9338c2ecf20Sopenharmony_ci bld_label = (const void *)tlv->val; 9348c2ecf20Sopenharmony_ci break; 9358c2ecf20Sopenharmony_ci case QTN_TLV_ID_HW_ID: 9368c2ecf20Sopenharmony_ci hw_id = (const void *)tlv->val; 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci case QTN_TLV_ID_CALIBRATION_VER: 9398c2ecf20Sopenharmony_ci calibration_ver = (const void *)tlv->val; 9408c2ecf20Sopenharmony_ci break; 9418c2ecf20Sopenharmony_ci case QTN_TLV_ID_UBOOT_VER: 9428c2ecf20Sopenharmony_ci uboot_ver = (const void *)tlv->val; 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci case QTN_TLV_ID_BITMAP: 9458c2ecf20Sopenharmony_ci memcpy(hwinfo->hw_capab, tlv->val, 9468c2ecf20Sopenharmony_ci min(sizeof(hwinfo->hw_capab), (size_t)tlv_len)); 9478c2ecf20Sopenharmony_ci break; 9488c2ecf20Sopenharmony_ci default: 9498c2ecf20Sopenharmony_ci break; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (!qlink_tlv_parsing_ok(tlv, resp->info, info_len)) { 9548c2ecf20Sopenharmony_ci pr_err("Malformed TLV buffer\n"); 9558c2ecf20Sopenharmony_ci return -EINVAL; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci pr_info("\nBuild name: %s\n" 9598c2ecf20Sopenharmony_ci "Build revision: %s\n" 9608c2ecf20Sopenharmony_ci "Build type: %s\n" 9618c2ecf20Sopenharmony_ci "Build label: %s\n" 9628c2ecf20Sopenharmony_ci "Build timestamp: %lu\n" 9638c2ecf20Sopenharmony_ci "Platform ID: %lu\n" 9648c2ecf20Sopenharmony_ci "Hardware ID: %s\n" 9658c2ecf20Sopenharmony_ci "Calibration version: %s\n" 9668c2ecf20Sopenharmony_ci "U-Boot version: %s\n" 9678c2ecf20Sopenharmony_ci "Hardware version: 0x%08x\n" 9688c2ecf20Sopenharmony_ci "Qlink ver: %u.%u\n" 9698c2ecf20Sopenharmony_ci "MACs map: %#x\n" 9708c2ecf20Sopenharmony_ci "Chains Rx-Tx: %ux%u\n" 9718c2ecf20Sopenharmony_ci "FW version: 0x%x\n", 9728c2ecf20Sopenharmony_ci bld_name, bld_rev, bld_type, bld_label, 9738c2ecf20Sopenharmony_ci (unsigned long)bld_tmstamp, 9748c2ecf20Sopenharmony_ci (unsigned long)plat_id, 9758c2ecf20Sopenharmony_ci hw_id, calibration_ver, uboot_ver, hw_ver, 9768c2ecf20Sopenharmony_ci QLINK_VER_MAJOR(bus->hw_info.ql_proto_ver), 9778c2ecf20Sopenharmony_ci QLINK_VER_MINOR(bus->hw_info.ql_proto_ver), 9788c2ecf20Sopenharmony_ci hwinfo->mac_bitmap, 9798c2ecf20Sopenharmony_ci hwinfo->total_rx_chain, hwinfo->total_tx_chain, 9808c2ecf20Sopenharmony_ci hwinfo->fw_ver); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci strlcpy(hwinfo->fw_version, bld_label, sizeof(hwinfo->fw_version)); 9838c2ecf20Sopenharmony_ci hwinfo->hw_version = hw_ver; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci return 0; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic void 9898c2ecf20Sopenharmony_ciqtnf_parse_wowlan_info(struct qtnf_wmac *mac, 9908c2ecf20Sopenharmony_ci const struct qlink_wowlan_capab_data *wowlan) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct qtnf_mac_info *mac_info = &mac->macinfo; 9938c2ecf20Sopenharmony_ci const struct qlink_wowlan_support *data1; 9948c2ecf20Sopenharmony_ci struct wiphy_wowlan_support *supp; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci supp = kzalloc(sizeof(*supp), GFP_KERNEL); 9978c2ecf20Sopenharmony_ci if (!supp) 9988c2ecf20Sopenharmony_ci return; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci switch (le16_to_cpu(wowlan->version)) { 10018c2ecf20Sopenharmony_ci case 0x1: 10028c2ecf20Sopenharmony_ci data1 = (struct qlink_wowlan_support *)wowlan->data; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci supp->flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT; 10058c2ecf20Sopenharmony_ci supp->n_patterns = le32_to_cpu(data1->n_patterns); 10068c2ecf20Sopenharmony_ci supp->pattern_max_len = le32_to_cpu(data1->pattern_max_len); 10078c2ecf20Sopenharmony_ci supp->pattern_min_len = le32_to_cpu(data1->pattern_min_len); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci mac_info->wowlan = supp; 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci default: 10128c2ecf20Sopenharmony_ci pr_warn("MAC%u: unsupported WoWLAN version 0x%x\n", 10138c2ecf20Sopenharmony_ci mac->macid, le16_to_cpu(wowlan->version)); 10148c2ecf20Sopenharmony_ci kfree(supp); 10158c2ecf20Sopenharmony_ci break; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic int 10208c2ecf20Sopenharmony_ciqtnf_parse_variable_mac_info(struct qtnf_wmac *mac, 10218c2ecf20Sopenharmony_ci const struct qlink_resp_get_mac_info *resp, 10228c2ecf20Sopenharmony_ci size_t tlv_buf_size) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci struct ieee80211_iface_combination *comb = mac->macinfo.if_comb; 10258c2ecf20Sopenharmony_ci size_t n_comb = 0; 10268c2ecf20Sopenharmony_ci struct ieee80211_iface_limit *limits; 10278c2ecf20Sopenharmony_ci const struct qlink_iface_limit_record *rec; 10288c2ecf20Sopenharmony_ci const struct qlink_iface_limit *lim; 10298c2ecf20Sopenharmony_ci const struct qlink_wowlan_capab_data *wowlan; 10308c2ecf20Sopenharmony_ci u16 rec_len; 10318c2ecf20Sopenharmony_ci u16 tlv_type; 10328c2ecf20Sopenharmony_ci u16 tlv_value_len; 10338c2ecf20Sopenharmony_ci const struct qlink_tlv_hdr *tlv; 10348c2ecf20Sopenharmony_ci u8 *ext_capa = NULL; 10358c2ecf20Sopenharmony_ci u8 *ext_capa_mask = NULL; 10368c2ecf20Sopenharmony_ci u8 ext_capa_len = 0; 10378c2ecf20Sopenharmony_ci u8 ext_capa_mask_len = 0; 10388c2ecf20Sopenharmony_ci int i = 0; 10398c2ecf20Sopenharmony_ci struct ieee80211_reg_rule *rule; 10408c2ecf20Sopenharmony_ci unsigned int rule_idx = 0; 10418c2ecf20Sopenharmony_ci const struct qlink_tlv_reg_rule *tlv_rule; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES)) 10448c2ecf20Sopenharmony_ci return -E2BIG; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci mac->rd = kzalloc(struct_size(mac->rd, reg_rules, resp->n_reg_rules), 10478c2ecf20Sopenharmony_ci GFP_KERNEL); 10488c2ecf20Sopenharmony_ci if (!mac->rd) 10498c2ecf20Sopenharmony_ci return -ENOMEM; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci mac->rd->n_reg_rules = resp->n_reg_rules; 10528c2ecf20Sopenharmony_ci mac->rd->alpha2[0] = resp->alpha2[0]; 10538c2ecf20Sopenharmony_ci mac->rd->alpha2[1] = resp->alpha2[1]; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci switch (resp->dfs_region) { 10568c2ecf20Sopenharmony_ci case QLINK_DFS_FCC: 10578c2ecf20Sopenharmony_ci mac->rd->dfs_region = NL80211_DFS_FCC; 10588c2ecf20Sopenharmony_ci break; 10598c2ecf20Sopenharmony_ci case QLINK_DFS_ETSI: 10608c2ecf20Sopenharmony_ci mac->rd->dfs_region = NL80211_DFS_ETSI; 10618c2ecf20Sopenharmony_ci break; 10628c2ecf20Sopenharmony_ci case QLINK_DFS_JP: 10638c2ecf20Sopenharmony_ci mac->rd->dfs_region = NL80211_DFS_JP; 10648c2ecf20Sopenharmony_ci break; 10658c2ecf20Sopenharmony_ci case QLINK_DFS_UNSET: 10668c2ecf20Sopenharmony_ci default: 10678c2ecf20Sopenharmony_ci mac->rd->dfs_region = NL80211_DFS_UNSET; 10688c2ecf20Sopenharmony_ci break; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci qlink_for_each_tlv(tlv, resp->var_info, tlv_buf_size) { 10728c2ecf20Sopenharmony_ci tlv_type = le16_to_cpu(tlv->type); 10738c2ecf20Sopenharmony_ci tlv_value_len = le16_to_cpu(tlv->len); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci switch (tlv_type) { 10768c2ecf20Sopenharmony_ci case QTN_TLV_ID_IFACE_LIMIT: 10778c2ecf20Sopenharmony_ci if (unlikely(!comb)) { 10788c2ecf20Sopenharmony_ci pr_warn("MAC%u: no combinations advertised\n", 10798c2ecf20Sopenharmony_ci mac->macid); 10808c2ecf20Sopenharmony_ci return -EINVAL; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (n_comb >= mac->macinfo.n_if_comb) { 10848c2ecf20Sopenharmony_ci pr_warn("MAC%u: combinations count exceeded\n", 10858c2ecf20Sopenharmony_ci mac->macid); 10868c2ecf20Sopenharmony_ci n_comb++; 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci rec = (void *)tlv->val; 10918c2ecf20Sopenharmony_ci rec_len = sizeof(*rec) + rec->n_limits * sizeof(*lim); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (unlikely(tlv_value_len != rec_len)) { 10948c2ecf20Sopenharmony_ci pr_warn("MAC%u: record %zu size mismatch\n", 10958c2ecf20Sopenharmony_ci mac->macid, n_comb); 10968c2ecf20Sopenharmony_ci return -EINVAL; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci limits = kcalloc(rec->n_limits, sizeof(*limits), 11008c2ecf20Sopenharmony_ci GFP_KERNEL); 11018c2ecf20Sopenharmony_ci if (!limits) 11028c2ecf20Sopenharmony_ci return -ENOMEM; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci comb[n_comb].num_different_channels = 11058c2ecf20Sopenharmony_ci rec->num_different_channels; 11068c2ecf20Sopenharmony_ci comb[n_comb].max_interfaces = 11078c2ecf20Sopenharmony_ci le16_to_cpu(rec->max_interfaces); 11088c2ecf20Sopenharmony_ci comb[n_comb].n_limits = rec->n_limits; 11098c2ecf20Sopenharmony_ci comb[n_comb].limits = limits; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci for (i = 0; i < rec->n_limits; i++) { 11128c2ecf20Sopenharmony_ci lim = &rec->limits[i]; 11138c2ecf20Sopenharmony_ci limits[i].max = le16_to_cpu(lim->max_num); 11148c2ecf20Sopenharmony_ci limits[i].types = 11158c2ecf20Sopenharmony_ci qlink_iface_type_to_nl_mask(le16_to_cpu(lim->type)); 11168c2ecf20Sopenharmony_ci pr_debug("MAC%u: comb[%zu]: MAX:%u TYPES:%.4X\n", 11178c2ecf20Sopenharmony_ci mac->macid, n_comb, 11188c2ecf20Sopenharmony_ci limits[i].max, limits[i].types); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci n_comb++; 11228c2ecf20Sopenharmony_ci break; 11238c2ecf20Sopenharmony_ci case WLAN_EID_EXT_CAPABILITY: 11248c2ecf20Sopenharmony_ci if (unlikely(tlv_value_len > U8_MAX)) 11258c2ecf20Sopenharmony_ci return -EINVAL; 11268c2ecf20Sopenharmony_ci ext_capa = (u8 *)tlv->val; 11278c2ecf20Sopenharmony_ci ext_capa_len = tlv_value_len; 11288c2ecf20Sopenharmony_ci break; 11298c2ecf20Sopenharmony_ci case QTN_TLV_ID_EXT_CAPABILITY_MASK: 11308c2ecf20Sopenharmony_ci if (unlikely(tlv_value_len > U8_MAX)) 11318c2ecf20Sopenharmony_ci return -EINVAL; 11328c2ecf20Sopenharmony_ci ext_capa_mask = (u8 *)tlv->val; 11338c2ecf20Sopenharmony_ci ext_capa_mask_len = tlv_value_len; 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci case QTN_TLV_ID_WOWLAN_CAPAB: 11368c2ecf20Sopenharmony_ci if (tlv_value_len < sizeof(*wowlan)) 11378c2ecf20Sopenharmony_ci return -EINVAL; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci wowlan = (void *)tlv->val; 11408c2ecf20Sopenharmony_ci if (!le16_to_cpu(wowlan->len)) { 11418c2ecf20Sopenharmony_ci pr_warn("MAC%u: skip empty WoWLAN data\n", 11428c2ecf20Sopenharmony_ci mac->macid); 11438c2ecf20Sopenharmony_ci break; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci rec_len = sizeof(*wowlan) + le16_to_cpu(wowlan->len); 11478c2ecf20Sopenharmony_ci if (unlikely(tlv_value_len != rec_len)) { 11488c2ecf20Sopenharmony_ci pr_warn("MAC%u: WoWLAN data size mismatch\n", 11498c2ecf20Sopenharmony_ci mac->macid); 11508c2ecf20Sopenharmony_ci return -EINVAL; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci kfree(mac->macinfo.wowlan); 11548c2ecf20Sopenharmony_ci mac->macinfo.wowlan = NULL; 11558c2ecf20Sopenharmony_ci qtnf_parse_wowlan_info(mac, wowlan); 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci case QTN_TLV_ID_REG_RULE: 11588c2ecf20Sopenharmony_ci if (rule_idx >= resp->n_reg_rules) { 11598c2ecf20Sopenharmony_ci pr_warn("unexpected number of rules: %u\n", 11608c2ecf20Sopenharmony_ci resp->n_reg_rules); 11618c2ecf20Sopenharmony_ci return -EINVAL; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (tlv_value_len != sizeof(*tlv_rule) - sizeof(*tlv)) { 11658c2ecf20Sopenharmony_ci pr_warn("malformed TLV 0x%.2X; LEN: %u\n", 11668c2ecf20Sopenharmony_ci tlv_type, tlv_value_len); 11678c2ecf20Sopenharmony_ci return -EINVAL; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci tlv_rule = (const struct qlink_tlv_reg_rule *)tlv; 11718c2ecf20Sopenharmony_ci rule = &mac->rd->reg_rules[rule_idx++]; 11728c2ecf20Sopenharmony_ci qlink_utils_regrule_q2nl(rule, tlv_rule); 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci default: 11758c2ecf20Sopenharmony_ci pr_warn("MAC%u: unknown TLV type %u\n", 11768c2ecf20Sopenharmony_ci mac->macid, tlv_type); 11778c2ecf20Sopenharmony_ci break; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (!qlink_tlv_parsing_ok(tlv, resp->var_info, tlv_buf_size)) { 11828c2ecf20Sopenharmony_ci pr_err("Malformed TLV buffer\n"); 11838c2ecf20Sopenharmony_ci return -EINVAL; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci if (mac->macinfo.n_if_comb != n_comb) { 11878c2ecf20Sopenharmony_ci pr_err("MAC%u: combination mismatch: reported=%zu parsed=%zu\n", 11888c2ecf20Sopenharmony_ci mac->macid, mac->macinfo.n_if_comb, n_comb); 11898c2ecf20Sopenharmony_ci return -EINVAL; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (ext_capa_len != ext_capa_mask_len) { 11938c2ecf20Sopenharmony_ci pr_err("MAC%u: ext_capa/_mask lengths mismatch: %u != %u\n", 11948c2ecf20Sopenharmony_ci mac->macid, ext_capa_len, ext_capa_mask_len); 11958c2ecf20Sopenharmony_ci return -EINVAL; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci if (rule_idx != resp->n_reg_rules) { 11998c2ecf20Sopenharmony_ci pr_warn("unexpected number of rules: expected %u got %u\n", 12008c2ecf20Sopenharmony_ci resp->n_reg_rules, rule_idx); 12018c2ecf20Sopenharmony_ci return -EINVAL; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (ext_capa_len > 0) { 12058c2ecf20Sopenharmony_ci ext_capa = kmemdup(ext_capa, ext_capa_len, GFP_KERNEL); 12068c2ecf20Sopenharmony_ci if (!ext_capa) 12078c2ecf20Sopenharmony_ci return -ENOMEM; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci ext_capa_mask = 12108c2ecf20Sopenharmony_ci kmemdup(ext_capa_mask, ext_capa_mask_len, GFP_KERNEL); 12118c2ecf20Sopenharmony_ci if (!ext_capa_mask) { 12128c2ecf20Sopenharmony_ci kfree(ext_capa); 12138c2ecf20Sopenharmony_ci return -ENOMEM; 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci } else { 12168c2ecf20Sopenharmony_ci ext_capa = NULL; 12178c2ecf20Sopenharmony_ci ext_capa_mask = NULL; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci qtnf_mac_ext_caps_free(mac); 12218c2ecf20Sopenharmony_ci mac->macinfo.extended_capabilities = ext_capa; 12228c2ecf20Sopenharmony_ci mac->macinfo.extended_capabilities_mask = ext_capa_mask; 12238c2ecf20Sopenharmony_ci mac->macinfo.extended_capabilities_len = ext_capa_len; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci return 0; 12268c2ecf20Sopenharmony_ci} 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_cistatic int 12298c2ecf20Sopenharmony_ciqtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac, 12308c2ecf20Sopenharmony_ci const struct qlink_resp_get_mac_info *resp_info) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci struct qtnf_mac_info *mac_info; 12338c2ecf20Sopenharmony_ci struct qtnf_vif *vif; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci qtnf_mac_iface_comb_free(mac); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci mac_info = &mac->macinfo; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci mac_info->bands_cap = resp_info->bands_cap; 12408c2ecf20Sopenharmony_ci ether_addr_copy(mac->macaddr, resp_info->dev_mac); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci vif = qtnf_mac_get_base_vif(mac); 12438c2ecf20Sopenharmony_ci if (vif) 12448c2ecf20Sopenharmony_ci ether_addr_copy(vif->mac_addr, mac->macaddr); 12458c2ecf20Sopenharmony_ci else 12468c2ecf20Sopenharmony_ci pr_err("could not get valid base vif\n"); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci mac_info->num_tx_chain = resp_info->num_tx_chain; 12498c2ecf20Sopenharmony_ci mac_info->num_rx_chain = resp_info->num_rx_chain; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci mac_info->max_ap_assoc_sta = le16_to_cpu(resp_info->max_ap_assoc_sta); 12528c2ecf20Sopenharmony_ci mac_info->radar_detect_widths = 12538c2ecf20Sopenharmony_ci qlink_chan_width_mask_to_nl(le16_to_cpu( 12548c2ecf20Sopenharmony_ci resp_info->radar_detect_widths)); 12558c2ecf20Sopenharmony_ci mac_info->max_acl_mac_addrs = le16_to_cpu(resp_info->max_acl_mac_addrs); 12568c2ecf20Sopenharmony_ci mac_info->frag_thr = le32_to_cpu(resp_info->frag_threshold); 12578c2ecf20Sopenharmony_ci mac_info->rts_thr = le32_to_cpu(resp_info->rts_threshold); 12588c2ecf20Sopenharmony_ci mac_info->sretry_limit = resp_info->retry_short; 12598c2ecf20Sopenharmony_ci mac_info->lretry_limit = resp_info->retry_long; 12608c2ecf20Sopenharmony_ci mac_info->coverage_class = resp_info->coverage_class; 12618c2ecf20Sopenharmony_ci mac_info->max_scan_ssids = resp_info->max_scan_ssids; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci memcpy(&mac_info->ht_cap_mod_mask, &resp_info->ht_cap_mod_mask, 12648c2ecf20Sopenharmony_ci sizeof(mac_info->ht_cap_mod_mask)); 12658c2ecf20Sopenharmony_ci memcpy(&mac_info->vht_cap_mod_mask, &resp_info->vht_cap_mod_mask, 12668c2ecf20Sopenharmony_ci sizeof(mac_info->vht_cap_mod_mask)); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci mac_info->n_if_comb = resp_info->n_iface_combinations; 12698c2ecf20Sopenharmony_ci mac_info->if_comb = kcalloc(mac->macinfo.n_if_comb, 12708c2ecf20Sopenharmony_ci sizeof(*mac->macinfo.if_comb), 12718c2ecf20Sopenharmony_ci GFP_KERNEL); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (!mac->macinfo.if_comb) 12748c2ecf20Sopenharmony_ci return -ENOMEM; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci return 0; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic void qtnf_cmd_resp_band_fill_htcap(const u8 *info, 12808c2ecf20Sopenharmony_ci struct ieee80211_sta_ht_cap *bcap) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci const struct ieee80211_ht_cap *ht_cap = 12838c2ecf20Sopenharmony_ci (const struct ieee80211_ht_cap *)info; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci bcap->ht_supported = true; 12868c2ecf20Sopenharmony_ci bcap->cap = le16_to_cpu(ht_cap->cap_info); 12878c2ecf20Sopenharmony_ci bcap->ampdu_factor = 12888c2ecf20Sopenharmony_ci ht_cap->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR; 12898c2ecf20Sopenharmony_ci bcap->ampdu_density = 12908c2ecf20Sopenharmony_ci (ht_cap->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 12918c2ecf20Sopenharmony_ci IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; 12928c2ecf20Sopenharmony_ci memcpy(&bcap->mcs, &ht_cap->mcs, sizeof(bcap->mcs)); 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic void qtnf_cmd_resp_band_fill_vhtcap(const u8 *info, 12968c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *bcap) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci const struct ieee80211_vht_cap *vht_cap = 12998c2ecf20Sopenharmony_ci (const struct ieee80211_vht_cap *)info; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci bcap->vht_supported = true; 13028c2ecf20Sopenharmony_ci bcap->cap = le32_to_cpu(vht_cap->vht_cap_info); 13038c2ecf20Sopenharmony_ci memcpy(&bcap->vht_mcs, &vht_cap->supp_mcs, sizeof(bcap->vht_mcs)); 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic void qtnf_cmd_conv_iftype(struct ieee80211_sband_iftype_data 13078c2ecf20Sopenharmony_ci *iftype_data, 13088c2ecf20Sopenharmony_ci const struct qlink_sband_iftype_data 13098c2ecf20Sopenharmony_ci *qlink_data) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci iftype_data->types_mask = le16_to_cpu(qlink_data->types_mask); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci iftype_data->he_cap.has_he = true; 13148c2ecf20Sopenharmony_ci memcpy(&iftype_data->he_cap.he_cap_elem, &qlink_data->he_cap_elem, 13158c2ecf20Sopenharmony_ci sizeof(qlink_data->he_cap_elem)); 13168c2ecf20Sopenharmony_ci memcpy(iftype_data->he_cap.ppe_thres, qlink_data->ppe_thres, 13178c2ecf20Sopenharmony_ci ARRAY_SIZE(qlink_data->ppe_thres)); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80 = 13208c2ecf20Sopenharmony_ci qlink_data->he_mcs_nss_supp.rx_mcs_80; 13218c2ecf20Sopenharmony_ci iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80 = 13228c2ecf20Sopenharmony_ci qlink_data->he_mcs_nss_supp.tx_mcs_80; 13238c2ecf20Sopenharmony_ci iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_160 = 13248c2ecf20Sopenharmony_ci qlink_data->he_mcs_nss_supp.rx_mcs_160; 13258c2ecf20Sopenharmony_ci iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160 = 13268c2ecf20Sopenharmony_ci qlink_data->he_mcs_nss_supp.tx_mcs_160; 13278c2ecf20Sopenharmony_ci iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80p80 = 13288c2ecf20Sopenharmony_ci qlink_data->he_mcs_nss_supp.rx_mcs_80p80; 13298c2ecf20Sopenharmony_ci iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80p80 = 13308c2ecf20Sopenharmony_ci qlink_data->he_mcs_nss_supp.tx_mcs_80p80; 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_cistatic int qtnf_cmd_band_fill_iftype(const u8 *data, 13348c2ecf20Sopenharmony_ci struct ieee80211_supported_band *band) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci unsigned int i; 13378c2ecf20Sopenharmony_ci struct ieee80211_sband_iftype_data *iftype_data; 13388c2ecf20Sopenharmony_ci const struct qlink_tlv_iftype_data *tlv = 13398c2ecf20Sopenharmony_ci (const struct qlink_tlv_iftype_data *)data; 13408c2ecf20Sopenharmony_ci size_t payload_len = tlv->n_iftype_data * sizeof(*tlv->iftype_data) + 13418c2ecf20Sopenharmony_ci sizeof(*tlv) - 13428c2ecf20Sopenharmony_ci sizeof(struct qlink_tlv_hdr); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (tlv->hdr.len != cpu_to_le16(payload_len)) { 13458c2ecf20Sopenharmony_ci pr_err("bad IFTYPE_DATA TLV len %u\n", tlv->hdr.len); 13468c2ecf20Sopenharmony_ci return -EINVAL; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci kfree(band->iftype_data); 13508c2ecf20Sopenharmony_ci band->iftype_data = NULL; 13518c2ecf20Sopenharmony_ci band->n_iftype_data = tlv->n_iftype_data; 13528c2ecf20Sopenharmony_ci if (band->n_iftype_data == 0) 13538c2ecf20Sopenharmony_ci return 0; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci iftype_data = kcalloc(band->n_iftype_data, sizeof(*iftype_data), 13568c2ecf20Sopenharmony_ci GFP_KERNEL); 13578c2ecf20Sopenharmony_ci if (!iftype_data) { 13588c2ecf20Sopenharmony_ci band->n_iftype_data = 0; 13598c2ecf20Sopenharmony_ci return -ENOMEM; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci band->iftype_data = iftype_data; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci for (i = 0; i < band->n_iftype_data; i++) 13648c2ecf20Sopenharmony_ci qtnf_cmd_conv_iftype(iftype_data++, &tlv->iftype_data[i]); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci return 0; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic int 13708c2ecf20Sopenharmony_ciqtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band, 13718c2ecf20Sopenharmony_ci struct qlink_resp_band_info_get *resp, 13728c2ecf20Sopenharmony_ci size_t payload_len) 13738c2ecf20Sopenharmony_ci{ 13748c2ecf20Sopenharmony_ci u16 tlv_type; 13758c2ecf20Sopenharmony_ci size_t tlv_dlen; 13768c2ecf20Sopenharmony_ci const struct qlink_tlv_hdr *tlv; 13778c2ecf20Sopenharmony_ci const struct qlink_channel *qchan; 13788c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 13798c2ecf20Sopenharmony_ci unsigned int chidx = 0; 13808c2ecf20Sopenharmony_ci u32 qflags; 13818c2ecf20Sopenharmony_ci int ret = -EINVAL; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci memset(&band->ht_cap, 0, sizeof(band->ht_cap)); 13848c2ecf20Sopenharmony_ci memset(&band->vht_cap, 0, sizeof(band->vht_cap)); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (band->channels) { 13878c2ecf20Sopenharmony_ci if (band->n_channels == resp->num_chans) { 13888c2ecf20Sopenharmony_ci memset(band->channels, 0, 13898c2ecf20Sopenharmony_ci sizeof(*band->channels) * band->n_channels); 13908c2ecf20Sopenharmony_ci } else { 13918c2ecf20Sopenharmony_ci kfree(band->channels); 13928c2ecf20Sopenharmony_ci band->n_channels = 0; 13938c2ecf20Sopenharmony_ci band->channels = NULL; 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci band->n_channels = resp->num_chans; 13988c2ecf20Sopenharmony_ci if (band->n_channels == 0) 13998c2ecf20Sopenharmony_ci return 0; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (!band->channels) 14028c2ecf20Sopenharmony_ci band->channels = kcalloc(band->n_channels, sizeof(*chan), 14038c2ecf20Sopenharmony_ci GFP_KERNEL); 14048c2ecf20Sopenharmony_ci if (!band->channels) { 14058c2ecf20Sopenharmony_ci band->n_channels = 0; 14068c2ecf20Sopenharmony_ci return -ENOMEM; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci qlink_for_each_tlv(tlv, resp->info, payload_len) { 14108c2ecf20Sopenharmony_ci tlv_type = le16_to_cpu(tlv->type); 14118c2ecf20Sopenharmony_ci tlv_dlen = le16_to_cpu(tlv->len); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci switch (tlv_type) { 14148c2ecf20Sopenharmony_ci case QTN_TLV_ID_CHANNEL: 14158c2ecf20Sopenharmony_ci if (unlikely(tlv_dlen != sizeof(*qchan))) { 14168c2ecf20Sopenharmony_ci pr_err("invalid channel TLV len %zu\n", 14178c2ecf20Sopenharmony_ci tlv_dlen); 14188c2ecf20Sopenharmony_ci goto error_ret; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (chidx == band->n_channels) { 14228c2ecf20Sopenharmony_ci pr_err("too many channel TLVs\n"); 14238c2ecf20Sopenharmony_ci goto error_ret; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci qchan = (const struct qlink_channel *)tlv->val; 14278c2ecf20Sopenharmony_ci chan = &band->channels[chidx++]; 14288c2ecf20Sopenharmony_ci qflags = le32_to_cpu(qchan->flags); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci chan->hw_value = le16_to_cpu(qchan->hw_value); 14318c2ecf20Sopenharmony_ci chan->band = band->band; 14328c2ecf20Sopenharmony_ci chan->center_freq = le16_to_cpu(qchan->center_freq); 14338c2ecf20Sopenharmony_ci chan->max_antenna_gain = (int)qchan->max_antenna_gain; 14348c2ecf20Sopenharmony_ci chan->max_power = (int)qchan->max_power; 14358c2ecf20Sopenharmony_ci chan->max_reg_power = (int)qchan->max_reg_power; 14368c2ecf20Sopenharmony_ci chan->beacon_found = qchan->beacon_found; 14378c2ecf20Sopenharmony_ci chan->dfs_cac_ms = le32_to_cpu(qchan->dfs_cac_ms); 14388c2ecf20Sopenharmony_ci chan->flags = 0; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_DISABLED) 14418c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_DISABLED; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_NO_IR) 14448c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_IR; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_NO_HT40PLUS) 14478c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_HT40PLUS; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_NO_HT40MINUS) 14508c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_HT40MINUS; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_NO_OFDM) 14538c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_OFDM; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_NO_80MHZ) 14568c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_80MHZ; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_NO_160MHZ) 14598c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_160MHZ; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_INDOOR_ONLY) 14628c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_INDOOR_ONLY; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_IR_CONCURRENT) 14658c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_IR_CONCURRENT; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_NO_20MHZ) 14688c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_20MHZ; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_NO_10MHZ) 14718c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_NO_10MHZ; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (qflags & QLINK_CHAN_RADAR) { 14748c2ecf20Sopenharmony_ci chan->flags |= IEEE80211_CHAN_RADAR; 14758c2ecf20Sopenharmony_ci chan->dfs_state_entered = jiffies; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (qchan->dfs_state == QLINK_DFS_USABLE) 14788c2ecf20Sopenharmony_ci chan->dfs_state = NL80211_DFS_USABLE; 14798c2ecf20Sopenharmony_ci else if (qchan->dfs_state == 14808c2ecf20Sopenharmony_ci QLINK_DFS_AVAILABLE) 14818c2ecf20Sopenharmony_ci chan->dfs_state = NL80211_DFS_AVAILABLE; 14828c2ecf20Sopenharmony_ci else 14838c2ecf20Sopenharmony_ci chan->dfs_state = 14848c2ecf20Sopenharmony_ci NL80211_DFS_UNAVAILABLE; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci pr_debug("chan=%d flags=%#x max_pow=%d max_reg_pow=%d\n", 14888c2ecf20Sopenharmony_ci chan->hw_value, chan->flags, chan->max_power, 14898c2ecf20Sopenharmony_ci chan->max_reg_power); 14908c2ecf20Sopenharmony_ci break; 14918c2ecf20Sopenharmony_ci case WLAN_EID_HT_CAPABILITY: 14928c2ecf20Sopenharmony_ci if (unlikely(tlv_dlen != 14938c2ecf20Sopenharmony_ci sizeof(struct ieee80211_ht_cap))) { 14948c2ecf20Sopenharmony_ci pr_err("bad HTCAP TLV len %zu\n", tlv_dlen); 14958c2ecf20Sopenharmony_ci goto error_ret; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci qtnf_cmd_resp_band_fill_htcap(tlv->val, &band->ht_cap); 14998c2ecf20Sopenharmony_ci break; 15008c2ecf20Sopenharmony_ci case WLAN_EID_VHT_CAPABILITY: 15018c2ecf20Sopenharmony_ci if (unlikely(tlv_dlen != 15028c2ecf20Sopenharmony_ci sizeof(struct ieee80211_vht_cap))) { 15038c2ecf20Sopenharmony_ci pr_err("bad VHTCAP TLV len %zu\n", tlv_dlen); 15048c2ecf20Sopenharmony_ci goto error_ret; 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci qtnf_cmd_resp_band_fill_vhtcap(tlv->val, 15088c2ecf20Sopenharmony_ci &band->vht_cap); 15098c2ecf20Sopenharmony_ci break; 15108c2ecf20Sopenharmony_ci case QTN_TLV_ID_IFTYPE_DATA: 15118c2ecf20Sopenharmony_ci ret = qtnf_cmd_band_fill_iftype((const uint8_t *)tlv, 15128c2ecf20Sopenharmony_ci band); 15138c2ecf20Sopenharmony_ci if (ret) 15148c2ecf20Sopenharmony_ci goto error_ret; 15158c2ecf20Sopenharmony_ci break; 15168c2ecf20Sopenharmony_ci default: 15178c2ecf20Sopenharmony_ci pr_warn("unknown TLV type: %#x\n", tlv_type); 15188c2ecf20Sopenharmony_ci break; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (!qlink_tlv_parsing_ok(tlv, resp->info, payload_len)) { 15238c2ecf20Sopenharmony_ci pr_err("Malformed TLV buffer\n"); 15248c2ecf20Sopenharmony_ci goto error_ret; 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci if (band->n_channels != chidx) { 15288c2ecf20Sopenharmony_ci pr_err("channel count mismatch: reported=%d, parsed=%d\n", 15298c2ecf20Sopenharmony_ci band->n_channels, chidx); 15308c2ecf20Sopenharmony_ci goto error_ret; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci return 0; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_cierror_ret: 15368c2ecf20Sopenharmony_ci kfree(band->channels); 15378c2ecf20Sopenharmony_ci band->channels = NULL; 15388c2ecf20Sopenharmony_ci band->n_channels = 0; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci return ret; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ciint qtnf_cmd_get_mac_info(struct qtnf_wmac *mac) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb, *resp_skb = NULL; 15468c2ecf20Sopenharmony_ci const struct qlink_resp_get_mac_info *resp; 15478c2ecf20Sopenharmony_ci size_t var_data_len = 0; 15488c2ecf20Sopenharmony_ci int ret = 0; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, 15518c2ecf20Sopenharmony_ci QLINK_CMD_MAC_INFO, 15528c2ecf20Sopenharmony_ci sizeof(struct qlink_cmd)); 15538c2ecf20Sopenharmony_ci if (!cmd_skb) 15548c2ecf20Sopenharmony_ci return -ENOMEM; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci qtnf_bus_lock(mac->bus); 15578c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, 15588c2ecf20Sopenharmony_ci sizeof(*resp), &var_data_len); 15598c2ecf20Sopenharmony_ci if (ret) 15608c2ecf20Sopenharmony_ci goto out; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci resp = (const struct qlink_resp_get_mac_info *)resp_skb->data; 15638c2ecf20Sopenharmony_ci ret = qtnf_cmd_resp_proc_mac_info(mac, resp); 15648c2ecf20Sopenharmony_ci if (ret) 15658c2ecf20Sopenharmony_ci goto out; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci ret = qtnf_parse_variable_mac_info(mac, resp, var_data_len); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ciout: 15708c2ecf20Sopenharmony_ci qtnf_bus_unlock(mac->bus); 15718c2ecf20Sopenharmony_ci consume_skb(resp_skb); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci return ret; 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ciint qtnf_cmd_get_hw_info(struct qtnf_bus *bus) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb, *resp_skb = NULL; 15798c2ecf20Sopenharmony_ci const struct qlink_resp_get_hw_info *resp; 15808c2ecf20Sopenharmony_ci size_t info_len = 0; 15818c2ecf20Sopenharmony_ci int ret = 0; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, 15848c2ecf20Sopenharmony_ci QLINK_CMD_GET_HW_INFO, 15858c2ecf20Sopenharmony_ci sizeof(struct qlink_cmd)); 15868c2ecf20Sopenharmony_ci if (!cmd_skb) 15878c2ecf20Sopenharmony_ci return -ENOMEM; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 15908c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, 15918c2ecf20Sopenharmony_ci sizeof(*resp), &info_len); 15928c2ecf20Sopenharmony_ci if (ret) 15938c2ecf20Sopenharmony_ci goto out; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci resp = (const struct qlink_resp_get_hw_info *)resp_skb->data; 15968c2ecf20Sopenharmony_ci ret = qtnf_cmd_resp_proc_hw_info(bus, resp, info_len); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ciout: 15998c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 16008c2ecf20Sopenharmony_ci consume_skb(resp_skb); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci return ret; 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ciint qtnf_cmd_band_info_get(struct qtnf_wmac *mac, 16068c2ecf20Sopenharmony_ci struct ieee80211_supported_band *band) 16078c2ecf20Sopenharmony_ci{ 16088c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb, *resp_skb = NULL; 16098c2ecf20Sopenharmony_ci struct qlink_cmd_band_info_get *cmd; 16108c2ecf20Sopenharmony_ci struct qlink_resp_band_info_get *resp; 16118c2ecf20Sopenharmony_ci size_t info_len = 0; 16128c2ecf20Sopenharmony_ci int ret = 0; 16138c2ecf20Sopenharmony_ci u8 qband = qlink_utils_band_cfg2q(band->band); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, 16168c2ecf20Sopenharmony_ci QLINK_CMD_BAND_INFO_GET, 16178c2ecf20Sopenharmony_ci sizeof(*cmd)); 16188c2ecf20Sopenharmony_ci if (!cmd_skb) 16198c2ecf20Sopenharmony_ci return -ENOMEM; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_band_info_get *)cmd_skb->data; 16228c2ecf20Sopenharmony_ci cmd->band = qband; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci qtnf_bus_lock(mac->bus); 16258c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, 16268c2ecf20Sopenharmony_ci sizeof(*resp), &info_len); 16278c2ecf20Sopenharmony_ci if (ret) 16288c2ecf20Sopenharmony_ci goto out; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci resp = (struct qlink_resp_band_info_get *)resp_skb->data; 16318c2ecf20Sopenharmony_ci if (resp->band != qband) { 16328c2ecf20Sopenharmony_ci pr_err("MAC%u: reply band %u != cmd band %u\n", mac->macid, 16338c2ecf20Sopenharmony_ci resp->band, qband); 16348c2ecf20Sopenharmony_ci ret = -EINVAL; 16358c2ecf20Sopenharmony_ci goto out; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci ret = qtnf_cmd_resp_fill_band_info(band, resp, info_len); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ciout: 16418c2ecf20Sopenharmony_ci qtnf_bus_unlock(mac->bus); 16428c2ecf20Sopenharmony_ci consume_skb(resp_skb); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci return ret; 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ciint qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed) 16488c2ecf20Sopenharmony_ci{ 16498c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(mac); 16508c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 16518c2ecf20Sopenharmony_ci int ret = 0; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, 16548c2ecf20Sopenharmony_ci QLINK_CMD_PHY_PARAMS_SET, 16558c2ecf20Sopenharmony_ci sizeof(struct qlink_cmd)); 16568c2ecf20Sopenharmony_ci if (!cmd_skb) 16578c2ecf20Sopenharmony_ci return -ENOMEM; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci qtnf_bus_lock(mac->bus); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (changed & WIPHY_PARAM_FRAG_THRESHOLD) 16628c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_FRAG_THRESH, 16638c2ecf20Sopenharmony_ci wiphy->frag_threshold); 16648c2ecf20Sopenharmony_ci if (changed & WIPHY_PARAM_RTS_THRESHOLD) 16658c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_RTS_THRESH, 16668c2ecf20Sopenharmony_ci wiphy->rts_threshold); 16678c2ecf20Sopenharmony_ci if (changed & WIPHY_PARAM_COVERAGE_CLASS) 16688c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS, 16698c2ecf20Sopenharmony_ci wiphy->coverage_class); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (changed & WIPHY_PARAM_RETRY_LONG) 16728c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_LRETRY_LIMIT, 16738c2ecf20Sopenharmony_ci wiphy->retry_long); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci if (changed & WIPHY_PARAM_RETRY_SHORT) 16768c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_SRETRY_LIMIT, 16778c2ecf20Sopenharmony_ci wiphy->retry_short); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(mac->bus, cmd_skb); 16808c2ecf20Sopenharmony_ci if (ret) 16818c2ecf20Sopenharmony_ci goto out; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ciout: 16848c2ecf20Sopenharmony_ci qtnf_bus_unlock(mac->bus); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci return ret; 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ciint qtnf_cmd_send_init_fw(struct qtnf_bus *bus) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci struct sk_buff *resp_skb = NULL; 16928c2ecf20Sopenharmony_ci struct qlink_resp_init_fw *resp; 16938c2ecf20Sopenharmony_ci struct qlink_cmd_init_fw *cmd; 16948c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 16958c2ecf20Sopenharmony_ci size_t info_len = 0; 16968c2ecf20Sopenharmony_ci int ret; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, 16998c2ecf20Sopenharmony_ci QLINK_CMD_FW_INIT, 17008c2ecf20Sopenharmony_ci sizeof(*cmd)); 17018c2ecf20Sopenharmony_ci if (!cmd_skb) 17028c2ecf20Sopenharmony_ci return -ENOMEM; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_init_fw *)cmd_skb->data; 17058c2ecf20Sopenharmony_ci cmd->qlink_proto_ver = cpu_to_le32(QLINK_PROTO_VER); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 17088c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, 17098c2ecf20Sopenharmony_ci sizeof(*resp), &info_len); 17108c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (ret) 17138c2ecf20Sopenharmony_ci goto out; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci resp = (struct qlink_resp_init_fw *)resp_skb->data; 17168c2ecf20Sopenharmony_ci bus->hw_info.ql_proto_ver = le32_to_cpu(resp->qlink_proto_ver); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ciout: 17198c2ecf20Sopenharmony_ci consume_skb(resp_skb); 17208c2ecf20Sopenharmony_ci return ret; 17218c2ecf20Sopenharmony_ci} 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_civoid qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus) 17248c2ecf20Sopenharmony_ci{ 17258c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, 17288c2ecf20Sopenharmony_ci QLINK_CMD_FW_DEINIT, 17298c2ecf20Sopenharmony_ci sizeof(struct qlink_cmd)); 17308c2ecf20Sopenharmony_ci if (!cmd_skb) 17318c2ecf20Sopenharmony_ci return; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 17348c2ecf20Sopenharmony_ci qtnf_cmd_send(bus, cmd_skb); 17358c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ciint qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, 17398c2ecf20Sopenharmony_ci const u8 *mac_addr, struct key_params *params) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 17428c2ecf20Sopenharmony_ci struct qlink_cmd_add_key *cmd; 17438c2ecf20Sopenharmony_ci int ret = 0; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 17468c2ecf20Sopenharmony_ci QLINK_CMD_ADD_KEY, 17478c2ecf20Sopenharmony_ci sizeof(*cmd)); 17488c2ecf20Sopenharmony_ci if (!cmd_skb) 17498c2ecf20Sopenharmony_ci return -ENOMEM; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_add_key *)cmd_skb->data; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci if (mac_addr) 17568c2ecf20Sopenharmony_ci ether_addr_copy(cmd->addr, mac_addr); 17578c2ecf20Sopenharmony_ci else 17588c2ecf20Sopenharmony_ci eth_broadcast_addr(cmd->addr); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci cmd->cipher = cpu_to_le32(params->cipher); 17618c2ecf20Sopenharmony_ci cmd->key_index = key_index; 17628c2ecf20Sopenharmony_ci cmd->pairwise = pairwise; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (params->key && params->key_len > 0) 17658c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_KEY, 17668c2ecf20Sopenharmony_ci params->key, 17678c2ecf20Sopenharmony_ci params->key_len); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci if (params->seq && params->seq_len > 0) 17708c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_SEQ, 17718c2ecf20Sopenharmony_ci params->seq, 17728c2ecf20Sopenharmony_ci params->seq_len); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 17758c2ecf20Sopenharmony_ci if (ret) 17768c2ecf20Sopenharmony_ci goto out; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ciout: 17798c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci return ret; 17828c2ecf20Sopenharmony_ci} 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ciint qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise, 17858c2ecf20Sopenharmony_ci const u8 *mac_addr) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 17888c2ecf20Sopenharmony_ci struct qlink_cmd_del_key *cmd; 17898c2ecf20Sopenharmony_ci int ret = 0; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 17928c2ecf20Sopenharmony_ci QLINK_CMD_DEL_KEY, 17938c2ecf20Sopenharmony_ci sizeof(*cmd)); 17948c2ecf20Sopenharmony_ci if (!cmd_skb) 17958c2ecf20Sopenharmony_ci return -ENOMEM; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_del_key *)cmd_skb->data; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (mac_addr) 18028c2ecf20Sopenharmony_ci ether_addr_copy(cmd->addr, mac_addr); 18038c2ecf20Sopenharmony_ci else 18048c2ecf20Sopenharmony_ci eth_broadcast_addr(cmd->addr); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci cmd->key_index = key_index; 18078c2ecf20Sopenharmony_ci cmd->pairwise = pairwise; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 18108c2ecf20Sopenharmony_ci if (ret) 18118c2ecf20Sopenharmony_ci goto out; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ciout: 18148c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci return ret; 18178c2ecf20Sopenharmony_ci} 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ciint qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index, 18208c2ecf20Sopenharmony_ci bool unicast, bool multicast) 18218c2ecf20Sopenharmony_ci{ 18228c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 18238c2ecf20Sopenharmony_ci struct qlink_cmd_set_def_key *cmd; 18248c2ecf20Sopenharmony_ci int ret = 0; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 18278c2ecf20Sopenharmony_ci QLINK_CMD_SET_DEFAULT_KEY, 18288c2ecf20Sopenharmony_ci sizeof(*cmd)); 18298c2ecf20Sopenharmony_ci if (!cmd_skb) 18308c2ecf20Sopenharmony_ci return -ENOMEM; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_set_def_key *)cmd_skb->data; 18358c2ecf20Sopenharmony_ci cmd->key_index = key_index; 18368c2ecf20Sopenharmony_ci cmd->unicast = unicast; 18378c2ecf20Sopenharmony_ci cmd->multicast = multicast; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 18408c2ecf20Sopenharmony_ci if (ret) 18418c2ecf20Sopenharmony_ci goto out; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ciout: 18448c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci return ret; 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ciint qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index) 18508c2ecf20Sopenharmony_ci{ 18518c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 18528c2ecf20Sopenharmony_ci struct qlink_cmd_set_def_mgmt_key *cmd; 18538c2ecf20Sopenharmony_ci int ret = 0; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 18568c2ecf20Sopenharmony_ci QLINK_CMD_SET_DEFAULT_MGMT_KEY, 18578c2ecf20Sopenharmony_ci sizeof(*cmd)); 18588c2ecf20Sopenharmony_ci if (!cmd_skb) 18598c2ecf20Sopenharmony_ci return -ENOMEM; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data; 18648c2ecf20Sopenharmony_ci cmd->key_index = key_index; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 18678c2ecf20Sopenharmony_ci if (ret) 18688c2ecf20Sopenharmony_ci goto out; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ciout: 18718c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci return ret; 18748c2ecf20Sopenharmony_ci} 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_cistatic u32 qtnf_encode_sta_flags(u32 flags) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci u32 code = 0; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci if (flags & BIT(NL80211_STA_FLAG_AUTHORIZED)) 18818c2ecf20Sopenharmony_ci code |= QLINK_STA_FLAG_AUTHORIZED; 18828c2ecf20Sopenharmony_ci if (flags & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) 18838c2ecf20Sopenharmony_ci code |= QLINK_STA_FLAG_SHORT_PREAMBLE; 18848c2ecf20Sopenharmony_ci if (flags & BIT(NL80211_STA_FLAG_WME)) 18858c2ecf20Sopenharmony_ci code |= QLINK_STA_FLAG_WME; 18868c2ecf20Sopenharmony_ci if (flags & BIT(NL80211_STA_FLAG_MFP)) 18878c2ecf20Sopenharmony_ci code |= QLINK_STA_FLAG_MFP; 18888c2ecf20Sopenharmony_ci if (flags & BIT(NL80211_STA_FLAG_AUTHENTICATED)) 18898c2ecf20Sopenharmony_ci code |= QLINK_STA_FLAG_AUTHENTICATED; 18908c2ecf20Sopenharmony_ci if (flags & BIT(NL80211_STA_FLAG_TDLS_PEER)) 18918c2ecf20Sopenharmony_ci code |= QLINK_STA_FLAG_TDLS_PEER; 18928c2ecf20Sopenharmony_ci if (flags & BIT(NL80211_STA_FLAG_ASSOCIATED)) 18938c2ecf20Sopenharmony_ci code |= QLINK_STA_FLAG_ASSOCIATED; 18948c2ecf20Sopenharmony_ci return code; 18958c2ecf20Sopenharmony_ci} 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ciint qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, 18988c2ecf20Sopenharmony_ci struct station_parameters *params) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 19018c2ecf20Sopenharmony_ci struct qlink_cmd_change_sta *cmd; 19028c2ecf20Sopenharmony_ci int ret = 0; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 19058c2ecf20Sopenharmony_ci QLINK_CMD_CHANGE_STA, 19068c2ecf20Sopenharmony_ci sizeof(*cmd)); 19078c2ecf20Sopenharmony_ci if (!cmd_skb) 19088c2ecf20Sopenharmony_ci return -ENOMEM; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_change_sta *)cmd_skb->data; 19138c2ecf20Sopenharmony_ci ether_addr_copy(cmd->sta_addr, mac); 19148c2ecf20Sopenharmony_ci cmd->flag_update.mask = 19158c2ecf20Sopenharmony_ci cpu_to_le32(qtnf_encode_sta_flags(params->sta_flags_mask)); 19168c2ecf20Sopenharmony_ci cmd->flag_update.value = 19178c2ecf20Sopenharmony_ci cpu_to_le32(qtnf_encode_sta_flags(params->sta_flags_set)); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci switch (vif->wdev.iftype) { 19208c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 19218c2ecf20Sopenharmony_ci cmd->if_type = cpu_to_le16(QLINK_IFTYPE_AP); 19228c2ecf20Sopenharmony_ci break; 19238c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 19248c2ecf20Sopenharmony_ci cmd->if_type = cpu_to_le16(QLINK_IFTYPE_STATION); 19258c2ecf20Sopenharmony_ci break; 19268c2ecf20Sopenharmony_ci default: 19278c2ecf20Sopenharmony_ci pr_err("unsupported iftype %d\n", vif->wdev.iftype); 19288c2ecf20Sopenharmony_ci dev_kfree_skb(cmd_skb); 19298c2ecf20Sopenharmony_ci ret = -EINVAL; 19308c2ecf20Sopenharmony_ci goto out; 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 19348c2ecf20Sopenharmony_ci if (ret) 19358c2ecf20Sopenharmony_ci goto out; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ciout: 19388c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci return ret; 19418c2ecf20Sopenharmony_ci} 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ciint qtnf_cmd_send_del_sta(struct qtnf_vif *vif, 19448c2ecf20Sopenharmony_ci struct station_del_parameters *params) 19458c2ecf20Sopenharmony_ci{ 19468c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 19478c2ecf20Sopenharmony_ci struct qlink_cmd_del_sta *cmd; 19488c2ecf20Sopenharmony_ci int ret = 0; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 19518c2ecf20Sopenharmony_ci QLINK_CMD_DEL_STA, 19528c2ecf20Sopenharmony_ci sizeof(*cmd)); 19538c2ecf20Sopenharmony_ci if (!cmd_skb) 19548c2ecf20Sopenharmony_ci return -ENOMEM; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_del_sta *)cmd_skb->data; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (params->mac) 19618c2ecf20Sopenharmony_ci ether_addr_copy(cmd->sta_addr, params->mac); 19628c2ecf20Sopenharmony_ci else 19638c2ecf20Sopenharmony_ci eth_broadcast_addr(cmd->sta_addr); /* flush all stations */ 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci cmd->subtype = params->subtype; 19668c2ecf20Sopenharmony_ci cmd->reason_code = cpu_to_le16(params->reason_code); 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 19698c2ecf20Sopenharmony_ci if (ret) 19708c2ecf20Sopenharmony_ci goto out; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ciout: 19738c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci return ret; 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_cistatic void qtnf_cmd_channel_tlv_add(struct sk_buff *cmd_skb, 19798c2ecf20Sopenharmony_ci const struct ieee80211_channel *sc) 19808c2ecf20Sopenharmony_ci{ 19818c2ecf20Sopenharmony_ci struct qlink_tlv_channel *tlv; 19828c2ecf20Sopenharmony_ci struct qlink_channel *qch; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci tlv = skb_put_zero(cmd_skb, sizeof(*tlv)); 19858c2ecf20Sopenharmony_ci qch = &tlv->chan; 19868c2ecf20Sopenharmony_ci tlv->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL); 19878c2ecf20Sopenharmony_ci tlv->hdr.len = cpu_to_le16(sizeof(*qch)); 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci qch->center_freq = cpu_to_le16(sc->center_freq); 19908c2ecf20Sopenharmony_ci qch->hw_value = cpu_to_le16(sc->hw_value); 19918c2ecf20Sopenharmony_ci qch->band = qlink_utils_band_cfg2q(sc->band); 19928c2ecf20Sopenharmony_ci qch->max_power = sc->max_power; 19938c2ecf20Sopenharmony_ci qch->max_reg_power = sc->max_reg_power; 19948c2ecf20Sopenharmony_ci qch->max_antenna_gain = sc->max_antenna_gain; 19958c2ecf20Sopenharmony_ci qch->beacon_found = sc->beacon_found; 19968c2ecf20Sopenharmony_ci qch->dfs_state = qlink_utils_dfs_state_cfg2q(sc->dfs_state); 19978c2ecf20Sopenharmony_ci qch->flags = cpu_to_le32(qlink_utils_chflags_cfg2q(sc->flags)); 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb, 20018c2ecf20Sopenharmony_ci const u8 *mac_addr, 20028c2ecf20Sopenharmony_ci const u8 *mac_addr_mask) 20038c2ecf20Sopenharmony_ci{ 20048c2ecf20Sopenharmony_ci struct qlink_random_mac_addr *randmac; 20058c2ecf20Sopenharmony_ci struct qlink_tlv_hdr *hdr = 20068c2ecf20Sopenharmony_ci skb_put(cmd_skb, sizeof(*hdr) + sizeof(*randmac)); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci hdr->type = cpu_to_le16(QTN_TLV_ID_RANDOM_MAC_ADDR); 20098c2ecf20Sopenharmony_ci hdr->len = cpu_to_le16(sizeof(*randmac)); 20108c2ecf20Sopenharmony_ci randmac = (struct qlink_random_mac_addr *)hdr->val; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci memcpy(randmac->mac_addr, mac_addr, ETH_ALEN); 20138c2ecf20Sopenharmony_ci memcpy(randmac->mac_addr_mask, mac_addr_mask, ETH_ALEN); 20148c2ecf20Sopenharmony_ci} 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ciint qtnf_cmd_send_scan(struct qtnf_wmac *mac) 20178c2ecf20Sopenharmony_ci{ 20188c2ecf20Sopenharmony_ci struct cfg80211_scan_request *scan_req = mac->scan_req; 20198c2ecf20Sopenharmony_ci u16 dwell_passive = QTNF_SCAN_DWELL_PASSIVE_DEFAULT; 20208c2ecf20Sopenharmony_ci u16 dwell_active = QTNF_SCAN_DWELL_ACTIVE_DEFAULT; 20218c2ecf20Sopenharmony_ci struct wireless_dev *wdev = scan_req->wdev; 20228c2ecf20Sopenharmony_ci struct ieee80211_channel *sc; 20238c2ecf20Sopenharmony_ci struct qlink_cmd_scan *cmd; 20248c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 20258c2ecf20Sopenharmony_ci int n_channels = 0; 20268c2ecf20Sopenharmony_ci u64 flags = 0; 20278c2ecf20Sopenharmony_ci int count; 20288c2ecf20Sopenharmony_ci int ret; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, 20318c2ecf20Sopenharmony_ci QLINK_CMD_SCAN, 20328c2ecf20Sopenharmony_ci sizeof(*cmd)); 20338c2ecf20Sopenharmony_ci if (!cmd_skb) 20348c2ecf20Sopenharmony_ci return -ENOMEM; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_scan *)cmd_skb->data; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci if (scan_req->duration) { 20398c2ecf20Sopenharmony_ci dwell_active = scan_req->duration; 20408c2ecf20Sopenharmony_ci dwell_passive = scan_req->duration; 20418c2ecf20Sopenharmony_ci } else if (wdev->iftype == NL80211_IFTYPE_STATION && 20428c2ecf20Sopenharmony_ci wdev->current_bss) { 20438c2ecf20Sopenharmony_ci /* let device select dwell based on traffic conditions */ 20448c2ecf20Sopenharmony_ci dwell_active = QTNF_SCAN_TIME_AUTO; 20458c2ecf20Sopenharmony_ci dwell_passive = QTNF_SCAN_TIME_AUTO; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci cmd->n_ssids = cpu_to_le16(scan_req->n_ssids); 20498c2ecf20Sopenharmony_ci for (count = 0; count < scan_req->n_ssids; ++count) { 20508c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, 20518c2ecf20Sopenharmony_ci scan_req->ssids[count].ssid, 20528c2ecf20Sopenharmony_ci scan_req->ssids[count].ssid_len); 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci if (scan_req->ie_len != 0) 20568c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_PROBE_REQ, 20578c2ecf20Sopenharmony_ci scan_req->ie, scan_req->ie_len); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci for (count = 0; count < scan_req->n_channels; ++count) { 20608c2ecf20Sopenharmony_ci sc = scan_req->channels[count]; 20618c2ecf20Sopenharmony_ci if (sc->flags & IEEE80211_CHAN_DISABLED) 20628c2ecf20Sopenharmony_ci continue; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci pr_debug("[MAC%u] scan chan=%d, freq=%d, flags=%#x\n", 20658c2ecf20Sopenharmony_ci mac->macid, sc->hw_value, sc->center_freq, 20668c2ecf20Sopenharmony_ci sc->flags); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci qtnf_cmd_channel_tlv_add(cmd_skb, sc); 20698c2ecf20Sopenharmony_ci ++n_channels; 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci if (scan_req->flags & NL80211_SCAN_FLAG_FLUSH) 20738c2ecf20Sopenharmony_ci flags |= QLINK_SCAN_FLAG_FLUSH; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci if (scan_req->duration_mandatory) 20768c2ecf20Sopenharmony_ci flags |= QLINK_SCAN_FLAG_DURATION_MANDATORY; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci cmd->n_channels = cpu_to_le16(n_channels); 20798c2ecf20Sopenharmony_ci cmd->active_dwell = cpu_to_le16(dwell_active); 20808c2ecf20Sopenharmony_ci cmd->passive_dwell = cpu_to_le16(dwell_passive); 20818c2ecf20Sopenharmony_ci cmd->sample_duration = cpu_to_le16(QTNF_SCAN_SAMPLE_DURATION_DEFAULT); 20828c2ecf20Sopenharmony_ci cmd->flags = cpu_to_le64(flags); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci pr_debug("[MAC%u] %s scan dwell active=%u passive=%u duration=%u\n", 20858c2ecf20Sopenharmony_ci mac->macid, 20868c2ecf20Sopenharmony_ci scan_req->duration_mandatory ? "mandatory" : "max", 20878c2ecf20Sopenharmony_ci dwell_active, dwell_passive, 20888c2ecf20Sopenharmony_ci QTNF_SCAN_SAMPLE_DURATION_DEFAULT); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci if (scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { 20918c2ecf20Sopenharmony_ci pr_debug("[MAC%u] scan with random addr=%pM, mask=%pM\n", 20928c2ecf20Sopenharmony_ci mac->macid, 20938c2ecf20Sopenharmony_ci scan_req->mac_addr, scan_req->mac_addr_mask); 20948c2ecf20Sopenharmony_ci qtnf_cmd_randmac_tlv_add(cmd_skb, scan_req->mac_addr, 20958c2ecf20Sopenharmony_ci scan_req->mac_addr_mask); 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci qtnf_bus_lock(mac->bus); 20998c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(mac->bus, cmd_skb); 21008c2ecf20Sopenharmony_ci qtnf_bus_unlock(mac->bus); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci return ret; 21038c2ecf20Sopenharmony_ci} 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ciint qtnf_cmd_send_connect(struct qtnf_vif *vif, 21068c2ecf20Sopenharmony_ci struct cfg80211_connect_params *sme) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 21098c2ecf20Sopenharmony_ci struct qlink_cmd_connect *cmd; 21108c2ecf20Sopenharmony_ci struct qlink_auth_encr *aen; 21118c2ecf20Sopenharmony_ci int ret; 21128c2ecf20Sopenharmony_ci int i; 21138c2ecf20Sopenharmony_ci u32 connect_flags = 0; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 21168c2ecf20Sopenharmony_ci QLINK_CMD_CONNECT, 21178c2ecf20Sopenharmony_ci sizeof(*cmd)); 21188c2ecf20Sopenharmony_ci if (!cmd_skb) 21198c2ecf20Sopenharmony_ci return -ENOMEM; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_connect *)cmd_skb->data; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci ether_addr_copy(cmd->bssid, vif->bssid); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci if (sme->bssid_hint) 21268c2ecf20Sopenharmony_ci ether_addr_copy(cmd->bssid_hint, sme->bssid_hint); 21278c2ecf20Sopenharmony_ci else 21288c2ecf20Sopenharmony_ci eth_zero_addr(cmd->bssid_hint); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci if (sme->prev_bssid) 21318c2ecf20Sopenharmony_ci ether_addr_copy(cmd->prev_bssid, sme->prev_bssid); 21328c2ecf20Sopenharmony_ci else 21338c2ecf20Sopenharmony_ci eth_zero_addr(cmd->prev_bssid); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci if ((sme->bg_scan_period >= 0) && 21368c2ecf20Sopenharmony_ci (sme->bg_scan_period <= SHRT_MAX)) 21378c2ecf20Sopenharmony_ci cmd->bg_scan_period = cpu_to_le16(sme->bg_scan_period); 21388c2ecf20Sopenharmony_ci else 21398c2ecf20Sopenharmony_ci cmd->bg_scan_period = cpu_to_le16(-1); /* use default value */ 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci if (sme->flags & ASSOC_REQ_DISABLE_HT) 21428c2ecf20Sopenharmony_ci connect_flags |= QLINK_STA_CONNECT_DISABLE_HT; 21438c2ecf20Sopenharmony_ci if (sme->flags & ASSOC_REQ_DISABLE_VHT) 21448c2ecf20Sopenharmony_ci connect_flags |= QLINK_STA_CONNECT_DISABLE_VHT; 21458c2ecf20Sopenharmony_ci if (sme->flags & ASSOC_REQ_USE_RRM) 21468c2ecf20Sopenharmony_ci connect_flags |= QLINK_STA_CONNECT_USE_RRM; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci cmd->flags = cpu_to_le32(connect_flags); 21498c2ecf20Sopenharmony_ci memcpy(&cmd->ht_capa, &sme->ht_capa, sizeof(cmd->ht_capa)); 21508c2ecf20Sopenharmony_ci memcpy(&cmd->ht_capa_mask, &sme->ht_capa_mask, 21518c2ecf20Sopenharmony_ci sizeof(cmd->ht_capa_mask)); 21528c2ecf20Sopenharmony_ci memcpy(&cmd->vht_capa, &sme->vht_capa, sizeof(cmd->vht_capa)); 21538c2ecf20Sopenharmony_ci memcpy(&cmd->vht_capa_mask, &sme->vht_capa_mask, 21548c2ecf20Sopenharmony_ci sizeof(cmd->vht_capa_mask)); 21558c2ecf20Sopenharmony_ci cmd->pbss = sme->pbss; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci aen = &cmd->aen; 21588c2ecf20Sopenharmony_ci aen->auth_type = sme->auth_type; 21598c2ecf20Sopenharmony_ci aen->privacy = !!sme->privacy; 21608c2ecf20Sopenharmony_ci cmd->mfp = sme->mfp; 21618c2ecf20Sopenharmony_ci aen->wpa_versions = cpu_to_le32(sme->crypto.wpa_versions); 21628c2ecf20Sopenharmony_ci aen->cipher_group = cpu_to_le32(sme->crypto.cipher_group); 21638c2ecf20Sopenharmony_ci aen->n_ciphers_pairwise = cpu_to_le32(sme->crypto.n_ciphers_pairwise); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) 21668c2ecf20Sopenharmony_ci aen->ciphers_pairwise[i] = 21678c2ecf20Sopenharmony_ci cpu_to_le32(sme->crypto.ciphers_pairwise[i]); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci aen->n_akm_suites = cpu_to_le32(sme->crypto.n_akm_suites); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) 21728c2ecf20Sopenharmony_ci aen->akm_suites[i] = cpu_to_le32(sme->crypto.akm_suites[i]); 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci aen->control_port = sme->crypto.control_port; 21758c2ecf20Sopenharmony_ci aen->control_port_no_encrypt = 21768c2ecf20Sopenharmony_ci sme->crypto.control_port_no_encrypt; 21778c2ecf20Sopenharmony_ci aen->control_port_ethertype = 21788c2ecf20Sopenharmony_ci cpu_to_le16(be16_to_cpu(sme->crypto.control_port_ethertype)); 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, sme->ssid, 21818c2ecf20Sopenharmony_ci sme->ssid_len); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci if (sme->ie_len != 0) 21848c2ecf20Sopenharmony_ci qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_ASSOC_REQ, 21858c2ecf20Sopenharmony_ci sme->ie, sme->ie_len); 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci if (sme->channel) 21888c2ecf20Sopenharmony_ci qtnf_cmd_channel_tlv_add(cmd_skb, sme->channel); 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 21918c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 21928c2ecf20Sopenharmony_ci if (ret) 21938c2ecf20Sopenharmony_ci goto out; 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ciout: 21968c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci return ret; 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ciint qtnf_cmd_send_external_auth(struct qtnf_vif *vif, 22028c2ecf20Sopenharmony_ci struct cfg80211_external_auth_params *auth) 22038c2ecf20Sopenharmony_ci{ 22048c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 22058c2ecf20Sopenharmony_ci struct qlink_cmd_external_auth *cmd; 22068c2ecf20Sopenharmony_ci int ret; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 22098c2ecf20Sopenharmony_ci QLINK_CMD_EXTERNAL_AUTH, 22108c2ecf20Sopenharmony_ci sizeof(*cmd)); 22118c2ecf20Sopenharmony_ci if (!cmd_skb) 22128c2ecf20Sopenharmony_ci return -ENOMEM; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_external_auth *)cmd_skb->data; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci ether_addr_copy(cmd->peer, auth->bssid); 22178c2ecf20Sopenharmony_ci cmd->status = cpu_to_le16(auth->status); 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 22208c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 22218c2ecf20Sopenharmony_ci if (ret) 22228c2ecf20Sopenharmony_ci goto out; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ciout: 22258c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci return ret; 22288c2ecf20Sopenharmony_ci} 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ciint qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code) 22318c2ecf20Sopenharmony_ci{ 22328c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 22338c2ecf20Sopenharmony_ci struct qlink_cmd_disconnect *cmd; 22348c2ecf20Sopenharmony_ci int ret; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 22378c2ecf20Sopenharmony_ci QLINK_CMD_DISCONNECT, 22388c2ecf20Sopenharmony_ci sizeof(*cmd)); 22398c2ecf20Sopenharmony_ci if (!cmd_skb) 22408c2ecf20Sopenharmony_ci return -ENOMEM; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_disconnect *)cmd_skb->data; 22458c2ecf20Sopenharmony_ci cmd->reason = cpu_to_le16(reason_code); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 22488c2ecf20Sopenharmony_ci if (ret) 22498c2ecf20Sopenharmony_ci goto out; 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ciout: 22528c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci return ret; 22558c2ecf20Sopenharmony_ci} 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ciint qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up) 22588c2ecf20Sopenharmony_ci{ 22598c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 22608c2ecf20Sopenharmony_ci struct qlink_cmd_updown *cmd; 22618c2ecf20Sopenharmony_ci int ret; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 22648c2ecf20Sopenharmony_ci QLINK_CMD_UPDOWN_INTF, 22658c2ecf20Sopenharmony_ci sizeof(*cmd)); 22668c2ecf20Sopenharmony_ci if (!cmd_skb) 22678c2ecf20Sopenharmony_ci return -ENOMEM; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_updown *)cmd_skb->data; 22708c2ecf20Sopenharmony_ci cmd->if_up = !!up; 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 22738c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 22748c2ecf20Sopenharmony_ci if (ret) 22758c2ecf20Sopenharmony_ci goto out; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ciout: 22788c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci return ret; 22818c2ecf20Sopenharmony_ci} 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ciint qtnf_cmd_reg_notify(struct qtnf_wmac *mac, struct regulatory_request *req, 22848c2ecf20Sopenharmony_ci bool slave_radar, bool dfs_offload) 22858c2ecf20Sopenharmony_ci{ 22868c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(mac); 22878c2ecf20Sopenharmony_ci struct qtnf_bus *bus = mac->bus; 22888c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 22898c2ecf20Sopenharmony_ci int ret; 22908c2ecf20Sopenharmony_ci struct qlink_cmd_reg_notify *cmd; 22918c2ecf20Sopenharmony_ci enum nl80211_band band; 22928c2ecf20Sopenharmony_ci const struct ieee80211_supported_band *cfg_band; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, 22958c2ecf20Sopenharmony_ci QLINK_CMD_REG_NOTIFY, 22968c2ecf20Sopenharmony_ci sizeof(*cmd)); 22978c2ecf20Sopenharmony_ci if (!cmd_skb) 22988c2ecf20Sopenharmony_ci return -ENOMEM; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_reg_notify *)cmd_skb->data; 23018c2ecf20Sopenharmony_ci cmd->alpha2[0] = req->alpha2[0]; 23028c2ecf20Sopenharmony_ci cmd->alpha2[1] = req->alpha2[1]; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci switch (req->initiator) { 23058c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_CORE: 23068c2ecf20Sopenharmony_ci cmd->initiator = QLINK_REGDOM_SET_BY_CORE; 23078c2ecf20Sopenharmony_ci break; 23088c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_USER: 23098c2ecf20Sopenharmony_ci cmd->initiator = QLINK_REGDOM_SET_BY_USER; 23108c2ecf20Sopenharmony_ci break; 23118c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_DRIVER: 23128c2ecf20Sopenharmony_ci cmd->initiator = QLINK_REGDOM_SET_BY_DRIVER; 23138c2ecf20Sopenharmony_ci break; 23148c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_COUNTRY_IE: 23158c2ecf20Sopenharmony_ci cmd->initiator = QLINK_REGDOM_SET_BY_COUNTRY_IE; 23168c2ecf20Sopenharmony_ci break; 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci switch (req->user_reg_hint_type) { 23208c2ecf20Sopenharmony_ci case NL80211_USER_REG_HINT_USER: 23218c2ecf20Sopenharmony_ci cmd->user_reg_hint_type = QLINK_USER_REG_HINT_USER; 23228c2ecf20Sopenharmony_ci break; 23238c2ecf20Sopenharmony_ci case NL80211_USER_REG_HINT_CELL_BASE: 23248c2ecf20Sopenharmony_ci cmd->user_reg_hint_type = QLINK_USER_REG_HINT_CELL_BASE; 23258c2ecf20Sopenharmony_ci break; 23268c2ecf20Sopenharmony_ci case NL80211_USER_REG_HINT_INDOOR: 23278c2ecf20Sopenharmony_ci cmd->user_reg_hint_type = QLINK_USER_REG_HINT_INDOOR; 23288c2ecf20Sopenharmony_ci break; 23298c2ecf20Sopenharmony_ci } 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci switch (req->dfs_region) { 23328c2ecf20Sopenharmony_ci case NL80211_DFS_FCC: 23338c2ecf20Sopenharmony_ci cmd->dfs_region = QLINK_DFS_FCC; 23348c2ecf20Sopenharmony_ci break; 23358c2ecf20Sopenharmony_ci case NL80211_DFS_ETSI: 23368c2ecf20Sopenharmony_ci cmd->dfs_region = QLINK_DFS_ETSI; 23378c2ecf20Sopenharmony_ci break; 23388c2ecf20Sopenharmony_ci case NL80211_DFS_JP: 23398c2ecf20Sopenharmony_ci cmd->dfs_region = QLINK_DFS_JP; 23408c2ecf20Sopenharmony_ci break; 23418c2ecf20Sopenharmony_ci default: 23428c2ecf20Sopenharmony_ci cmd->dfs_region = QLINK_DFS_UNSET; 23438c2ecf20Sopenharmony_ci break; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci cmd->slave_radar = slave_radar; 23478c2ecf20Sopenharmony_ci cmd->dfs_offload = dfs_offload; 23488c2ecf20Sopenharmony_ci cmd->num_channels = 0; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 23518c2ecf20Sopenharmony_ci unsigned int i; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci cfg_band = wiphy->bands[band]; 23548c2ecf20Sopenharmony_ci if (!cfg_band) 23558c2ecf20Sopenharmony_ci continue; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci cmd->num_channels += cfg_band->n_channels; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci for (i = 0; i < cfg_band->n_channels; ++i) { 23608c2ecf20Sopenharmony_ci qtnf_cmd_channel_tlv_add(cmd_skb, 23618c2ecf20Sopenharmony_ci &cfg_band->channels[i]); 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci } 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 23668c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(bus, cmd_skb); 23678c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci return ret; 23708c2ecf20Sopenharmony_ci} 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_cistatic int 23738c2ecf20Sopenharmony_ciqtnf_cmd_resp_proc_chan_stat_info(struct survey_info *survey, 23748c2ecf20Sopenharmony_ci const u8 *payload, size_t payload_len) 23758c2ecf20Sopenharmony_ci{ 23768c2ecf20Sopenharmony_ci const struct qlink_chan_stats *stats = NULL; 23778c2ecf20Sopenharmony_ci const struct qlink_tlv_hdr *tlv; 23788c2ecf20Sopenharmony_ci u16 tlv_value_len; 23798c2ecf20Sopenharmony_ci u16 tlv_type; 23808c2ecf20Sopenharmony_ci const u8 *map = NULL; 23818c2ecf20Sopenharmony_ci unsigned int map_len = 0; 23828c2ecf20Sopenharmony_ci unsigned int stats_len = 0; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci qlink_for_each_tlv(tlv, payload, payload_len) { 23858c2ecf20Sopenharmony_ci tlv_type = le16_to_cpu(tlv->type); 23868c2ecf20Sopenharmony_ci tlv_value_len = le16_to_cpu(tlv->len); 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci switch (tlv_type) { 23898c2ecf20Sopenharmony_ci case QTN_TLV_ID_BITMAP: 23908c2ecf20Sopenharmony_ci map = tlv->val; 23918c2ecf20Sopenharmony_ci map_len = tlv_value_len; 23928c2ecf20Sopenharmony_ci break; 23938c2ecf20Sopenharmony_ci case QTN_TLV_ID_CHANNEL_STATS: 23948c2ecf20Sopenharmony_ci stats = (struct qlink_chan_stats *)tlv->val; 23958c2ecf20Sopenharmony_ci stats_len = tlv_value_len; 23968c2ecf20Sopenharmony_ci break; 23978c2ecf20Sopenharmony_ci default: 23988c2ecf20Sopenharmony_ci pr_info("Unknown TLV type: %#x\n", tlv_type); 23998c2ecf20Sopenharmony_ci break; 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci } 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci if (!qlink_tlv_parsing_ok(tlv, payload, payload_len)) { 24048c2ecf20Sopenharmony_ci pr_err("Malformed TLV buffer\n"); 24058c2ecf20Sopenharmony_ci return -EINVAL; 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci if (!map || !stats) 24098c2ecf20Sopenharmony_ci return 0; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci#define qtnf_chan_stat_avail(stat_name, bitn) \ 24128c2ecf20Sopenharmony_ci (qtnf_utils_is_bit_set(map, bitn, map_len) && \ 24138c2ecf20Sopenharmony_ci (offsetofend(struct qlink_chan_stats, stat_name) <= stats_len)) 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci if (qtnf_chan_stat_avail(time_on, QLINK_CHAN_STAT_TIME_ON)) { 24168c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_TIME; 24178c2ecf20Sopenharmony_ci survey->time = le64_to_cpu(stats->time_on); 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci if (qtnf_chan_stat_avail(time_tx, QLINK_CHAN_STAT_TIME_TX)) { 24218c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_TIME_TX; 24228c2ecf20Sopenharmony_ci survey->time_tx = le64_to_cpu(stats->time_tx); 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci if (qtnf_chan_stat_avail(time_rx, QLINK_CHAN_STAT_TIME_RX)) { 24268c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_TIME_RX; 24278c2ecf20Sopenharmony_ci survey->time_rx = le64_to_cpu(stats->time_rx); 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci if (qtnf_chan_stat_avail(cca_busy, QLINK_CHAN_STAT_CCA_BUSY)) { 24318c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_TIME_BUSY; 24328c2ecf20Sopenharmony_ci survey->time_busy = le64_to_cpu(stats->cca_busy); 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci if (qtnf_chan_stat_avail(cca_busy_ext, QLINK_CHAN_STAT_CCA_BUSY_EXT)) { 24368c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_TIME_EXT_BUSY; 24378c2ecf20Sopenharmony_ci survey->time_ext_busy = le64_to_cpu(stats->cca_busy_ext); 24388c2ecf20Sopenharmony_ci } 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci if (qtnf_chan_stat_avail(time_scan, QLINK_CHAN_STAT_TIME_SCAN)) { 24418c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_TIME_SCAN; 24428c2ecf20Sopenharmony_ci survey->time_scan = le64_to_cpu(stats->time_scan); 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci if (qtnf_chan_stat_avail(chan_noise, QLINK_CHAN_STAT_CHAN_NOISE)) { 24468c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_NOISE_DBM; 24478c2ecf20Sopenharmony_ci survey->noise = stats->chan_noise; 24488c2ecf20Sopenharmony_ci } 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci#undef qtnf_chan_stat_avail 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci return 0; 24538c2ecf20Sopenharmony_ci} 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ciint qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u32 chan_freq, 24568c2ecf20Sopenharmony_ci struct survey_info *survey) 24578c2ecf20Sopenharmony_ci{ 24588c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb, *resp_skb = NULL; 24598c2ecf20Sopenharmony_ci struct qlink_cmd_get_chan_stats *cmd; 24608c2ecf20Sopenharmony_ci struct qlink_resp_get_chan_stats *resp; 24618c2ecf20Sopenharmony_ci size_t var_data_len = 0; 24628c2ecf20Sopenharmony_ci int ret = 0; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, 24658c2ecf20Sopenharmony_ci QLINK_CMD_CHAN_STATS, 24668c2ecf20Sopenharmony_ci sizeof(*cmd)); 24678c2ecf20Sopenharmony_ci if (!cmd_skb) 24688c2ecf20Sopenharmony_ci return -ENOMEM; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_get_chan_stats *)cmd_skb->data; 24718c2ecf20Sopenharmony_ci cmd->channel_freq = cpu_to_le32(chan_freq); 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci qtnf_bus_lock(mac->bus); 24748c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, 24758c2ecf20Sopenharmony_ci sizeof(*resp), &var_data_len); 24768c2ecf20Sopenharmony_ci qtnf_bus_unlock(mac->bus); 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci if (ret) 24798c2ecf20Sopenharmony_ci goto out; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci resp = (struct qlink_resp_get_chan_stats *)resp_skb->data; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci if (le32_to_cpu(resp->chan_freq) != chan_freq) { 24848c2ecf20Sopenharmony_ci pr_err("[MAC%u] channel stats freq %u != requested %u\n", 24858c2ecf20Sopenharmony_ci mac->macid, le32_to_cpu(resp->chan_freq), chan_freq); 24868c2ecf20Sopenharmony_ci ret = -EINVAL; 24878c2ecf20Sopenharmony_ci goto out; 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci ret = qtnf_cmd_resp_proc_chan_stat_info(survey, resp->info, 24918c2ecf20Sopenharmony_ci var_data_len); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ciout: 24948c2ecf20Sopenharmony_ci consume_skb(resp_skb); 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci return ret; 24978c2ecf20Sopenharmony_ci} 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ciint qtnf_cmd_send_chan_switch(struct qtnf_vif *vif, 25008c2ecf20Sopenharmony_ci struct cfg80211_csa_settings *params) 25018c2ecf20Sopenharmony_ci{ 25028c2ecf20Sopenharmony_ci struct qtnf_wmac *mac = vif->mac; 25038c2ecf20Sopenharmony_ci struct qlink_cmd_chan_switch *cmd; 25048c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 25058c2ecf20Sopenharmony_ci int ret; 25068c2ecf20Sopenharmony_ci u64 flags = 0; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid, 25098c2ecf20Sopenharmony_ci QLINK_CMD_CHAN_SWITCH, 25108c2ecf20Sopenharmony_ci sizeof(*cmd)); 25118c2ecf20Sopenharmony_ci if (!cmd_skb) 25128c2ecf20Sopenharmony_ci return -ENOMEM; 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci if (params->radar_required) 25158c2ecf20Sopenharmony_ci flags |= QLINK_CHAN_SW_RADAR_REQUIRED; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci if (params->block_tx) 25188c2ecf20Sopenharmony_ci flags |= QLINK_CHAN_SW_BLOCK_TX; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_chan_switch *)cmd_skb->data; 25218c2ecf20Sopenharmony_ci qlink_chandef_cfg2q(¶ms->chandef, &cmd->channel); 25228c2ecf20Sopenharmony_ci cmd->flags = cpu_to_le64(flags); 25238c2ecf20Sopenharmony_ci cmd->beacon_count = params->count; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci qtnf_bus_lock(mac->bus); 25268c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(mac->bus, cmd_skb); 25278c2ecf20Sopenharmony_ci qtnf_bus_unlock(mac->bus); 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci return ret; 25308c2ecf20Sopenharmony_ci} 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ciint qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef) 25338c2ecf20Sopenharmony_ci{ 25348c2ecf20Sopenharmony_ci struct qtnf_bus *bus = vif->mac->bus; 25358c2ecf20Sopenharmony_ci const struct qlink_resp_channel_get *resp; 25368c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 25378c2ecf20Sopenharmony_ci struct sk_buff *resp_skb = NULL; 25388c2ecf20Sopenharmony_ci int ret; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 25418c2ecf20Sopenharmony_ci QLINK_CMD_CHAN_GET, 25428c2ecf20Sopenharmony_ci sizeof(struct qlink_cmd)); 25438c2ecf20Sopenharmony_ci if (!cmd_skb) 25448c2ecf20Sopenharmony_ci return -ENOMEM; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 25478c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, 25488c2ecf20Sopenharmony_ci sizeof(*resp), NULL); 25498c2ecf20Sopenharmony_ci if (ret) 25508c2ecf20Sopenharmony_ci goto out; 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci resp = (const struct qlink_resp_channel_get *)resp_skb->data; 25538c2ecf20Sopenharmony_ci qlink_chandef_q2cfg(priv_to_wiphy(vif->mac), &resp->chan, chdef); 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ciout: 25568c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 25578c2ecf20Sopenharmony_ci consume_skb(resp_skb); 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci return ret; 25608c2ecf20Sopenharmony_ci} 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ciint qtnf_cmd_start_cac(const struct qtnf_vif *vif, 25638c2ecf20Sopenharmony_ci const struct cfg80211_chan_def *chdef, 25648c2ecf20Sopenharmony_ci u32 cac_time_ms) 25658c2ecf20Sopenharmony_ci{ 25668c2ecf20Sopenharmony_ci struct qtnf_bus *bus = vif->mac->bus; 25678c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 25688c2ecf20Sopenharmony_ci struct qlink_cmd_start_cac *cmd; 25698c2ecf20Sopenharmony_ci int ret; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 25728c2ecf20Sopenharmony_ci QLINK_CMD_START_CAC, 25738c2ecf20Sopenharmony_ci sizeof(*cmd)); 25748c2ecf20Sopenharmony_ci if (!cmd_skb) 25758c2ecf20Sopenharmony_ci return -ENOMEM; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_start_cac *)cmd_skb->data; 25788c2ecf20Sopenharmony_ci cmd->cac_time_ms = cpu_to_le32(cac_time_ms); 25798c2ecf20Sopenharmony_ci qlink_chandef_cfg2q(chdef, &cmd->chan); 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 25828c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(bus, cmd_skb); 25838c2ecf20Sopenharmony_ci if (ret) 25848c2ecf20Sopenharmony_ci goto out; 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ciout: 25878c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci return ret; 25908c2ecf20Sopenharmony_ci} 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ciint qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif, 25938c2ecf20Sopenharmony_ci const struct cfg80211_acl_data *params) 25948c2ecf20Sopenharmony_ci{ 25958c2ecf20Sopenharmony_ci struct qtnf_bus *bus = vif->mac->bus; 25968c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 25978c2ecf20Sopenharmony_ci struct qlink_tlv_hdr *tlv; 25988c2ecf20Sopenharmony_ci size_t acl_size = struct_size(params, mac_addrs, params->n_acl_entries); 25998c2ecf20Sopenharmony_ci int ret; 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 26028c2ecf20Sopenharmony_ci QLINK_CMD_SET_MAC_ACL, 26038c2ecf20Sopenharmony_ci sizeof(struct qlink_cmd)); 26048c2ecf20Sopenharmony_ci if (!cmd_skb) 26058c2ecf20Sopenharmony_ci return -ENOMEM; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci tlv = skb_put(cmd_skb, sizeof(*tlv) + round_up(acl_size, QLINK_ALIGN)); 26088c2ecf20Sopenharmony_ci tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA); 26098c2ecf20Sopenharmony_ci tlv->len = cpu_to_le16(acl_size); 26108c2ecf20Sopenharmony_ci qlink_acl_data_cfg2q(params, (struct qlink_acl_data *)tlv->val); 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 26138c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(bus, cmd_skb); 26148c2ecf20Sopenharmony_ci if (ret) 26158c2ecf20Sopenharmony_ci goto out; 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ciout: 26188c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci return ret; 26218c2ecf20Sopenharmony_ci} 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ciint qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout) 26248c2ecf20Sopenharmony_ci{ 26258c2ecf20Sopenharmony_ci struct qtnf_bus *bus = vif->mac->bus; 26268c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 26278c2ecf20Sopenharmony_ci struct qlink_cmd_pm_set *cmd; 26288c2ecf20Sopenharmony_ci int ret = 0; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 26318c2ecf20Sopenharmony_ci QLINK_CMD_PM_SET, sizeof(*cmd)); 26328c2ecf20Sopenharmony_ci if (!cmd_skb) 26338c2ecf20Sopenharmony_ci return -ENOMEM; 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_pm_set *)cmd_skb->data; 26368c2ecf20Sopenharmony_ci cmd->pm_mode = pm_mode; 26378c2ecf20Sopenharmony_ci cmd->pm_standby_timer = cpu_to_le32(timeout); 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(bus, cmd_skb); 26428c2ecf20Sopenharmony_ci if (ret) 26438c2ecf20Sopenharmony_ci goto out; 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ciout: 26468c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci return ret; 26498c2ecf20Sopenharmony_ci} 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ciint qtnf_cmd_get_tx_power(const struct qtnf_vif *vif, int *dbm) 26528c2ecf20Sopenharmony_ci{ 26538c2ecf20Sopenharmony_ci struct qtnf_bus *bus = vif->mac->bus; 26548c2ecf20Sopenharmony_ci const struct qlink_resp_txpwr *resp; 26558c2ecf20Sopenharmony_ci struct sk_buff *resp_skb = NULL; 26568c2ecf20Sopenharmony_ci struct qlink_cmd_txpwr *cmd; 26578c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 26588c2ecf20Sopenharmony_ci int ret = 0; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 26618c2ecf20Sopenharmony_ci QLINK_CMD_TXPWR, sizeof(*cmd)); 26628c2ecf20Sopenharmony_ci if (!cmd_skb) 26638c2ecf20Sopenharmony_ci return -ENOMEM; 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_txpwr *)cmd_skb->data; 26668c2ecf20Sopenharmony_ci cmd->op_type = QLINK_TXPWR_GET; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, 26718c2ecf20Sopenharmony_ci sizeof(*resp), NULL); 26728c2ecf20Sopenharmony_ci if (ret) 26738c2ecf20Sopenharmony_ci goto out; 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci resp = (const struct qlink_resp_txpwr *)resp_skb->data; 26768c2ecf20Sopenharmony_ci *dbm = MBM_TO_DBM(le32_to_cpu(resp->txpwr)); 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_ciout: 26798c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 26808c2ecf20Sopenharmony_ci consume_skb(resp_skb); 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci return ret; 26838c2ecf20Sopenharmony_ci} 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ciint qtnf_cmd_set_tx_power(const struct qtnf_vif *vif, 26868c2ecf20Sopenharmony_ci enum nl80211_tx_power_setting type, int mbm) 26878c2ecf20Sopenharmony_ci{ 26888c2ecf20Sopenharmony_ci struct qtnf_bus *bus = vif->mac->bus; 26898c2ecf20Sopenharmony_ci const struct qlink_resp_txpwr *resp; 26908c2ecf20Sopenharmony_ci struct sk_buff *resp_skb = NULL; 26918c2ecf20Sopenharmony_ci struct qlink_cmd_txpwr *cmd; 26928c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 26938c2ecf20Sopenharmony_ci int ret = 0; 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 26968c2ecf20Sopenharmony_ci QLINK_CMD_TXPWR, sizeof(*cmd)); 26978c2ecf20Sopenharmony_ci if (!cmd_skb) 26988c2ecf20Sopenharmony_ci return -ENOMEM; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_txpwr *)cmd_skb->data; 27018c2ecf20Sopenharmony_ci cmd->op_type = QLINK_TXPWR_SET; 27028c2ecf20Sopenharmony_ci cmd->txpwr_setting = type; 27038c2ecf20Sopenharmony_ci cmd->txpwr = cpu_to_le32(mbm); 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, 27088c2ecf20Sopenharmony_ci sizeof(*resp), NULL); 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 27118c2ecf20Sopenharmony_ci consume_skb(resp_skb); 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci return ret; 27148c2ecf20Sopenharmony_ci} 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ciint qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, 27178c2ecf20Sopenharmony_ci const struct cfg80211_wowlan *wowl) 27188c2ecf20Sopenharmony_ci{ 27198c2ecf20Sopenharmony_ci struct qtnf_bus *bus = vif->mac->bus; 27208c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 27218c2ecf20Sopenharmony_ci struct qlink_cmd_wowlan_set *cmd; 27228c2ecf20Sopenharmony_ci u32 triggers = 0; 27238c2ecf20Sopenharmony_ci int count = 0; 27248c2ecf20Sopenharmony_ci int ret = 0; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 27278c2ecf20Sopenharmony_ci QLINK_CMD_WOWLAN_SET, sizeof(*cmd)); 27288c2ecf20Sopenharmony_ci if (!cmd_skb) 27298c2ecf20Sopenharmony_ci return -ENOMEM; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_wowlan_set *)cmd_skb->data; 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci if (wowl) { 27368c2ecf20Sopenharmony_ci if (wowl->disconnect) 27378c2ecf20Sopenharmony_ci triggers |= QLINK_WOWLAN_TRIG_DISCONNECT; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci if (wowl->magic_pkt) 27408c2ecf20Sopenharmony_ci triggers |= QLINK_WOWLAN_TRIG_MAGIC_PKT; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci if (wowl->n_patterns && wowl->patterns) { 27438c2ecf20Sopenharmony_ci triggers |= QLINK_WOWLAN_TRIG_PATTERN_PKT; 27448c2ecf20Sopenharmony_ci while (count < wowl->n_patterns) { 27458c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_tlv_arr(cmd_skb, 27468c2ecf20Sopenharmony_ci QTN_TLV_ID_WOWLAN_PATTERN, 27478c2ecf20Sopenharmony_ci wowl->patterns[count].pattern, 27488c2ecf20Sopenharmony_ci wowl->patterns[count].pattern_len); 27498c2ecf20Sopenharmony_ci count++; 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci } 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci cmd->triggers = cpu_to_le32(triggers); 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(bus, cmd_skb); 27578c2ecf20Sopenharmony_ci if (ret) 27588c2ecf20Sopenharmony_ci goto out; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ciout: 27618c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 27628c2ecf20Sopenharmony_ci return ret; 27638c2ecf20Sopenharmony_ci} 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ciint qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain) 27668c2ecf20Sopenharmony_ci{ 27678c2ecf20Sopenharmony_ci struct qtnf_bus *bus = vif->mac->bus; 27688c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 27698c2ecf20Sopenharmony_ci struct qlink_cmd_ndev_changeupper *cmd; 27708c2ecf20Sopenharmony_ci int ret; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 27738c2ecf20Sopenharmony_ci QLINK_CMD_NDEV_EVENT, 27748c2ecf20Sopenharmony_ci sizeof(*cmd)); 27758c2ecf20Sopenharmony_ci if (!cmd_skb) 27768c2ecf20Sopenharmony_ci return -ENOMEM; 27778c2ecf20Sopenharmony_ci 27788c2ecf20Sopenharmony_ci pr_debug("[VIF%u.%u] set broadcast domain to %d\n", 27798c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, br_domain); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_ndev_changeupper *)cmd_skb->data; 27828c2ecf20Sopenharmony_ci cmd->nehdr.event = cpu_to_le16(QLINK_NDEV_EVENT_CHANGEUPPER); 27838c2ecf20Sopenharmony_ci cmd->upper_type = QLINK_NDEV_UPPER_TYPE_BRIDGE; 27848c2ecf20Sopenharmony_ci cmd->br_domain = cpu_to_le32(br_domain); 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci qtnf_bus_lock(bus); 27878c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(bus, cmd_skb); 27888c2ecf20Sopenharmony_ci qtnf_bus_unlock(bus); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (ret) 27918c2ecf20Sopenharmony_ci pr_err("[VIF%u.%u] failed to set broadcast domain\n", 27928c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid); 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci return ret; 27958c2ecf20Sopenharmony_ci} 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ciint qtnf_cmd_send_update_owe(struct qtnf_vif *vif, 27988c2ecf20Sopenharmony_ci struct cfg80211_update_owe_info *owe) 27998c2ecf20Sopenharmony_ci{ 28008c2ecf20Sopenharmony_ci struct qlink_cmd_update_owe *cmd; 28018c2ecf20Sopenharmony_ci struct sk_buff *cmd_skb; 28028c2ecf20Sopenharmony_ci int ret; 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci if (sizeof(*cmd) + owe->ie_len > QTNF_MAX_CMD_BUF_SIZE) { 28058c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: OWE update IEs too big: %zu\n", 28068c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, owe->ie_len); 28078c2ecf20Sopenharmony_ci return -E2BIG; 28088c2ecf20Sopenharmony_ci } 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, 28118c2ecf20Sopenharmony_ci QLINK_CMD_UPDATE_OWE, 28128c2ecf20Sopenharmony_ci sizeof(*cmd)); 28138c2ecf20Sopenharmony_ci if (!cmd_skb) 28148c2ecf20Sopenharmony_ci return -ENOMEM; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci cmd = (struct qlink_cmd_update_owe *)cmd_skb->data; 28178c2ecf20Sopenharmony_ci ether_addr_copy(cmd->peer, owe->peer); 28188c2ecf20Sopenharmony_ci cmd->status = cpu_to_le16(owe->status); 28198c2ecf20Sopenharmony_ci if (owe->ie_len && owe->ie) 28208c2ecf20Sopenharmony_ci qtnf_cmd_skb_put_buffer(cmd_skb, owe->ie, owe->ie_len); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci qtnf_bus_lock(vif->mac->bus); 28238c2ecf20Sopenharmony_ci ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); 28248c2ecf20Sopenharmony_ci if (ret) 28258c2ecf20Sopenharmony_ci goto out; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ciout: 28288c2ecf20Sopenharmony_ci qtnf_bus_unlock(vif->mac->bus); 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci return ret; 28318c2ecf20Sopenharmony_ci} 2832