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(&params->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