1ff233cb5SSergey Matyukevich // SPDX-License-Identifier: GPL-2.0+
2ff233cb5SSergey Matyukevich /* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */
398f44cb0SIgor Mitsyanko
498f44cb0SIgor Mitsyanko #include <linux/types.h>
598f44cb0SIgor Mitsyanko #include <linux/skbuff.h>
698f44cb0SIgor Mitsyanko
798f44cb0SIgor Mitsyanko #include "cfg80211.h"
898f44cb0SIgor Mitsyanko #include "core.h"
998f44cb0SIgor Mitsyanko #include "qlink.h"
1098f44cb0SIgor Mitsyanko #include "qlink_util.h"
1198f44cb0SIgor Mitsyanko #include "bus.h"
1298f44cb0SIgor Mitsyanko #include "commands.h"
1398f44cb0SIgor Mitsyanko
14501c3be1SIgor Mitsyanko /* Let device itself to select best values for current conditions */
15b63967caSIgor Mitsyanko #define QTNF_SCAN_TIME_AUTO 0
16b63967caSIgor Mitsyanko
17501c3be1SIgor Mitsyanko #define QTNF_SCAN_DWELL_ACTIVE_DEFAULT 90
18501c3be1SIgor Mitsyanko #define QTNF_SCAN_DWELL_PASSIVE_DEFAULT 100
19b63967caSIgor Mitsyanko #define QTNF_SCAN_SAMPLE_DURATION_DEFAULT QTNF_SCAN_TIME_AUTO
20b63967caSIgor Mitsyanko
qtnf_cmd_check_reply_header(const struct qlink_resp * resp,u16 cmd_id,u8 mac_id,u8 vif_id,size_t resp_size)2198f44cb0SIgor Mitsyanko static int qtnf_cmd_check_reply_header(const struct qlink_resp *resp,
2298f44cb0SIgor Mitsyanko u16 cmd_id, u8 mac_id, u8 vif_id,
2398f44cb0SIgor Mitsyanko size_t resp_size)
2498f44cb0SIgor Mitsyanko {
2598f44cb0SIgor Mitsyanko if (unlikely(le16_to_cpu(resp->cmd_id) != cmd_id)) {
2698f44cb0SIgor Mitsyanko pr_warn("VIF%u.%u CMD%x: bad cmd_id in response: 0x%.4X\n",
2798f44cb0SIgor Mitsyanko mac_id, vif_id, cmd_id, le16_to_cpu(resp->cmd_id));
2898f44cb0SIgor Mitsyanko return -EINVAL;
2998f44cb0SIgor Mitsyanko }
3098f44cb0SIgor Mitsyanko
3198f44cb0SIgor Mitsyanko if (unlikely(resp->macid != mac_id)) {
3298f44cb0SIgor Mitsyanko pr_warn("VIF%u.%u CMD%x: bad MAC in response: %u\n",
3398f44cb0SIgor Mitsyanko mac_id, vif_id, cmd_id, resp->macid);
3498f44cb0SIgor Mitsyanko return -EINVAL;
3598f44cb0SIgor Mitsyanko }
3698f44cb0SIgor Mitsyanko
3798f44cb0SIgor Mitsyanko if (unlikely(resp->vifid != vif_id)) {
3898f44cb0SIgor Mitsyanko pr_warn("VIF%u.%u CMD%x: bad VIF in response: %u\n",
3998f44cb0SIgor Mitsyanko mac_id, vif_id, cmd_id, resp->vifid);
4098f44cb0SIgor Mitsyanko return -EINVAL;
4198f44cb0SIgor Mitsyanko }
4298f44cb0SIgor Mitsyanko
4398f44cb0SIgor Mitsyanko if (unlikely(le16_to_cpu(resp->mhdr.len) < resp_size)) {
4498f44cb0SIgor Mitsyanko pr_warn("VIF%u.%u CMD%x: bad response size %u < %zu\n",
4598f44cb0SIgor Mitsyanko mac_id, vif_id, cmd_id,
4698f44cb0SIgor Mitsyanko le16_to_cpu(resp->mhdr.len), resp_size);
4798f44cb0SIgor Mitsyanko return -ENOSPC;
4898f44cb0SIgor Mitsyanko }
4998f44cb0SIgor Mitsyanko
5098f44cb0SIgor Mitsyanko return 0;
5198f44cb0SIgor Mitsyanko }
5298f44cb0SIgor Mitsyanko
qtnf_cmd_resp_result_decode(enum qlink_cmd_result qcode)5336e8c538SIgor Mitsyanko static int qtnf_cmd_resp_result_decode(enum qlink_cmd_result qcode)
5436e8c538SIgor Mitsyanko {
5536e8c538SIgor Mitsyanko switch (qcode) {
5636e8c538SIgor Mitsyanko case QLINK_CMD_RESULT_OK:
5736e8c538SIgor Mitsyanko return 0;
5836e8c538SIgor Mitsyanko case QLINK_CMD_RESULT_INVALID:
5936e8c538SIgor Mitsyanko return -EINVAL;
6036e8c538SIgor Mitsyanko case QLINK_CMD_RESULT_ENOTSUPP:
6136e8c538SIgor Mitsyanko return -ENOTSUPP;
6236e8c538SIgor Mitsyanko case QLINK_CMD_RESULT_ENOTFOUND:
6336e8c538SIgor Mitsyanko return -ENOENT;
6436e8c538SIgor Mitsyanko case QLINK_CMD_RESULT_EALREADY:
6536e8c538SIgor Mitsyanko return -EALREADY;
6636e8c538SIgor Mitsyanko case QLINK_CMD_RESULT_EADDRINUSE:
6736e8c538SIgor Mitsyanko return -EADDRINUSE;
6836e8c538SIgor Mitsyanko case QLINK_CMD_RESULT_EADDRNOTAVAIL:
6936e8c538SIgor Mitsyanko return -EADDRNOTAVAIL;
70126824f5SAndrey Shevchenko case QLINK_CMD_RESULT_EBUSY:
71126824f5SAndrey Shevchenko return -EBUSY;
7236e8c538SIgor Mitsyanko default:
7336e8c538SIgor Mitsyanko return -EFAULT;
7436e8c538SIgor Mitsyanko }
7536e8c538SIgor Mitsyanko }
7636e8c538SIgor Mitsyanko
qtnf_cmd_send_with_reply(struct qtnf_bus * bus,struct sk_buff * cmd_skb,struct sk_buff ** response_skb,size_t const_resp_size,size_t * var_resp_size)7798f44cb0SIgor Mitsyanko static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,
7898f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb,
7998f44cb0SIgor Mitsyanko struct sk_buff **response_skb,
8098f44cb0SIgor Mitsyanko size_t const_resp_size,
8198f44cb0SIgor Mitsyanko size_t *var_resp_size)
8298f44cb0SIgor Mitsyanko {
8398f44cb0SIgor Mitsyanko struct qlink_cmd *cmd;
841066bd19SSergey Matyukevich struct qlink_resp *resp = NULL;
8598f44cb0SIgor Mitsyanko struct sk_buff *resp_skb = NULL;
864a33f21cSSergey Matyukevich int resp_res = 0;
8798f44cb0SIgor Mitsyanko u16 cmd_id;
88c6ed298fSSergey Matyukevich u8 mac_id;
89c6ed298fSSergey Matyukevich u8 vif_id;
9098f44cb0SIgor Mitsyanko int ret;
9198f44cb0SIgor Mitsyanko
9298f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd *)cmd_skb->data;
9398f44cb0SIgor Mitsyanko cmd_id = le16_to_cpu(cmd->cmd_id);
9498f44cb0SIgor Mitsyanko mac_id = cmd->macid;
9598f44cb0SIgor Mitsyanko vif_id = cmd->vifid;
9698f44cb0SIgor Mitsyanko cmd->mhdr.len = cpu_to_le16(cmd_skb->len);
9798f44cb0SIgor Mitsyanko
983844dec0SSergey Matyukevich pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, cmd_id);
99c6ed298fSSergey Matyukevich
10083b00f6eSSergey Matyukevich if (!qtnf_fw_is_up(bus) && cmd_id != QLINK_CMD_FW_INIT) {
10198f44cb0SIgor Mitsyanko pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n",
1023844dec0SSergey Matyukevich mac_id, vif_id, cmd_id, bus->fw_state);
103b60769e2SDmitry Lebed dev_kfree_skb(cmd_skb);
10498f44cb0SIgor Mitsyanko return -ENODEV;
10598f44cb0SIgor Mitsyanko }
10698f44cb0SIgor Mitsyanko
10798f44cb0SIgor Mitsyanko ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb);
108c6ed298fSSergey Matyukevich if (ret)
10998f44cb0SIgor Mitsyanko goto out;
11098f44cb0SIgor Mitsyanko
1111066bd19SSergey Matyukevich if (WARN_ON(!resp_skb || !resp_skb->data)) {
1121066bd19SSergey Matyukevich ret = -EFAULT;
1131066bd19SSergey Matyukevich goto out;
1141066bd19SSergey Matyukevich }
1151066bd19SSergey Matyukevich
1161066bd19SSergey Matyukevich resp = (struct qlink_resp *)resp_skb->data;
1174a33f21cSSergey Matyukevich resp_res = le16_to_cpu(resp->result);
11898f44cb0SIgor Mitsyanko ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id,
11998f44cb0SIgor Mitsyanko const_resp_size);
120c6ed298fSSergey Matyukevich if (ret)
12198f44cb0SIgor Mitsyanko goto out;
12298f44cb0SIgor Mitsyanko
12398f44cb0SIgor Mitsyanko /* Return length of variable part of response */
12498f44cb0SIgor Mitsyanko if (response_skb && var_resp_size)
12598f44cb0SIgor Mitsyanko *var_resp_size = le16_to_cpu(resp->mhdr.len) - const_resp_size;
12698f44cb0SIgor Mitsyanko
12798f44cb0SIgor Mitsyanko out:
12898f44cb0SIgor Mitsyanko if (response_skb)
12998f44cb0SIgor Mitsyanko *response_skb = resp_skb;
13098f44cb0SIgor Mitsyanko else
13198f44cb0SIgor Mitsyanko consume_skb(resp_skb);
13298f44cb0SIgor Mitsyanko
1334a33f21cSSergey Matyukevich if (!ret)
1344a33f21cSSergey Matyukevich return qtnf_cmd_resp_result_decode(resp_res);
135c6ed298fSSergey Matyukevich
136c6ed298fSSergey Matyukevich pr_warn("VIF%u.%u: cmd 0x%.4X failed: %d\n",
1373844dec0SSergey Matyukevich mac_id, vif_id, cmd_id, ret);
138c6ed298fSSergey Matyukevich
13998f44cb0SIgor Mitsyanko return ret;
14098f44cb0SIgor Mitsyanko }
14198f44cb0SIgor Mitsyanko
qtnf_cmd_send(struct qtnf_bus * bus,struct sk_buff * cmd_skb)142c6ed298fSSergey Matyukevich static inline int qtnf_cmd_send(struct qtnf_bus *bus, struct sk_buff *cmd_skb)
14398f44cb0SIgor Mitsyanko {
144c6ed298fSSergey Matyukevich return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL,
14598f44cb0SIgor Mitsyanko sizeof(struct qlink_resp), NULL);
14698f44cb0SIgor Mitsyanko }
14798f44cb0SIgor Mitsyanko
qtnf_cmd_alloc_new_cmdskb(u8 macid,u8 vifid,u16 cmd_no,size_t cmd_size)14898f44cb0SIgor Mitsyanko static struct sk_buff *qtnf_cmd_alloc_new_cmdskb(u8 macid, u8 vifid, u16 cmd_no,
14998f44cb0SIgor Mitsyanko size_t cmd_size)
15098f44cb0SIgor Mitsyanko {
15198f44cb0SIgor Mitsyanko struct qlink_cmd *cmd;
15298f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
15398f44cb0SIgor Mitsyanko
15498f44cb0SIgor Mitsyanko cmd_skb = __dev_alloc_skb(sizeof(*cmd) +
15598f44cb0SIgor Mitsyanko QTNF_MAX_CMD_BUF_SIZE, GFP_KERNEL);
15698f44cb0SIgor Mitsyanko if (unlikely(!cmd_skb)) {
15798f44cb0SIgor Mitsyanko pr_err("VIF%u.%u CMD %u: alloc failed\n", macid, vifid, cmd_no);
15898f44cb0SIgor Mitsyanko return NULL;
15998f44cb0SIgor Mitsyanko }
16098f44cb0SIgor Mitsyanko
161b080db58SJohannes Berg skb_put_zero(cmd_skb, cmd_size);
16298f44cb0SIgor Mitsyanko
16398f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd *)cmd_skb->data;
16498f44cb0SIgor Mitsyanko cmd->mhdr.len = cpu_to_le16(cmd_skb->len);
16598f44cb0SIgor Mitsyanko cmd->mhdr.type = cpu_to_le16(QLINK_MSG_TYPE_CMD);
16698f44cb0SIgor Mitsyanko cmd->cmd_id = cpu_to_le16(cmd_no);
16798f44cb0SIgor Mitsyanko cmd->macid = macid;
16898f44cb0SIgor Mitsyanko cmd->vifid = vifid;
16998f44cb0SIgor Mitsyanko
17098f44cb0SIgor Mitsyanko return cmd_skb;
17198f44cb0SIgor Mitsyanko }
17298f44cb0SIgor Mitsyanko
qtnf_cmd_tlv_ie_set_add(struct sk_buff * cmd_skb,u8 frame_type,const u8 * buf,size_t len)17318b7470fSIgor Mitsyanko static void qtnf_cmd_tlv_ie_set_add(struct sk_buff *cmd_skb, u8 frame_type,
17418b7470fSIgor Mitsyanko const u8 *buf, size_t len)
17518b7470fSIgor Mitsyanko {
17618b7470fSIgor Mitsyanko struct qlink_tlv_ie_set *tlv;
17718b7470fSIgor Mitsyanko
1788b0b5f1bSIgor Mitsyanko tlv = (struct qlink_tlv_ie_set *)skb_put(cmd_skb, sizeof(*tlv) +
1798b0b5f1bSIgor Mitsyanko round_up(len, QLINK_ALIGN));
18018b7470fSIgor Mitsyanko tlv->hdr.type = cpu_to_le16(QTN_TLV_ID_IE_SET);
18118b7470fSIgor Mitsyanko tlv->hdr.len = cpu_to_le16(len + sizeof(*tlv) - sizeof(tlv->hdr));
18218b7470fSIgor Mitsyanko tlv->type = frame_type;
18318b7470fSIgor Mitsyanko tlv->flags = 0;
18418b7470fSIgor Mitsyanko
18518b7470fSIgor Mitsyanko if (len && buf)
18618b7470fSIgor Mitsyanko memcpy(tlv->ie_data, buf, len);
18718b7470fSIgor Mitsyanko }
18818b7470fSIgor Mitsyanko
qtnf_cmd_start_ap_can_fit(const struct qtnf_vif * vif,const struct cfg80211_ap_settings * s)18917011da0SIgor Mitsyanko static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
19017011da0SIgor Mitsyanko const struct cfg80211_ap_settings *s)
19198f44cb0SIgor Mitsyanko {
19217011da0SIgor Mitsyanko unsigned int len = sizeof(struct qlink_cmd_start_ap);
19398f44cb0SIgor Mitsyanko
1948b0b5f1bSIgor Mitsyanko len += round_up(s->ssid_len, QLINK_ALIGN);
1958b0b5f1bSIgor Mitsyanko len += round_up(s->beacon.head_len, QLINK_ALIGN);
1968b0b5f1bSIgor Mitsyanko len += round_up(s->beacon.tail_len, QLINK_ALIGN);
1978b0b5f1bSIgor Mitsyanko len += round_up(s->beacon.beacon_ies_len, QLINK_ALIGN);
1988b0b5f1bSIgor Mitsyanko len += round_up(s->beacon.proberesp_ies_len, QLINK_ALIGN);
1998b0b5f1bSIgor Mitsyanko len += round_up(s->beacon.assocresp_ies_len, QLINK_ALIGN);
2008b0b5f1bSIgor Mitsyanko len += round_up(s->beacon.probe_resp_len, QLINK_ALIGN);
20198f44cb0SIgor Mitsyanko
20217011da0SIgor Mitsyanko if (cfg80211_chandef_valid(&s->chandef))
20317011da0SIgor Mitsyanko len += sizeof(struct qlink_tlv_chandef);
20498f44cb0SIgor Mitsyanko
2058b0b5f1bSIgor Mitsyanko if (s->acl) {
2068b0b5f1bSIgor Mitsyanko unsigned int acl_len = struct_size(s->acl, mac_addrs,
2078b0b5f1bSIgor Mitsyanko s->acl->n_acl_entries);
2088b0b5f1bSIgor Mitsyanko
20933f98992SVasily Ulyanov len += sizeof(struct qlink_tlv_hdr) +
2108b0b5f1bSIgor Mitsyanko round_up(acl_len, QLINK_ALIGN);
2118b0b5f1bSIgor Mitsyanko }
212f1398fd2SVasily Ulyanov
21317011da0SIgor Mitsyanko if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) {
21417011da0SIgor Mitsyanko pr_err("VIF%u.%u: can not fit AP settings: %u\n",
21517011da0SIgor Mitsyanko vif->mac->macid, vif->vifid, len);
21617011da0SIgor Mitsyanko return false;
21798f44cb0SIgor Mitsyanko }
21898f44cb0SIgor Mitsyanko
21917011da0SIgor Mitsyanko return true;
22098f44cb0SIgor Mitsyanko }
22198f44cb0SIgor Mitsyanko
qtnf_cmd_tlv_ie_ext_add(struct sk_buff * cmd_skb,u8 eid_ext,const void * buf,size_t len)222df0af4c7SMikhail Karpenko static void qtnf_cmd_tlv_ie_ext_add(struct sk_buff *cmd_skb, u8 eid_ext,
223df0af4c7SMikhail Karpenko const void *buf, size_t len)
224df0af4c7SMikhail Karpenko {
225df0af4c7SMikhail Karpenko struct qlink_tlv_ext_ie *tlv;
226df0af4c7SMikhail Karpenko
227df0af4c7SMikhail Karpenko tlv = (struct qlink_tlv_ext_ie *)skb_put(cmd_skb, sizeof(*tlv) + len);
228df0af4c7SMikhail Karpenko tlv->hdr.type = cpu_to_le16(WLAN_EID_EXTENSION);
229df0af4c7SMikhail Karpenko tlv->hdr.len = cpu_to_le16(sizeof(*tlv) + len - sizeof(tlv->hdr));
230df0af4c7SMikhail Karpenko tlv->eid_ext = eid_ext;
231df0af4c7SMikhail Karpenko
232df0af4c7SMikhail Karpenko if (len && buf)
233df0af4c7SMikhail Karpenko memcpy(tlv->ie_data, buf, len);
234df0af4c7SMikhail Karpenko }
235df0af4c7SMikhail Karpenko
qtnf_cmd_send_start_ap(struct qtnf_vif * vif,const struct cfg80211_ap_settings * s)23617011da0SIgor Mitsyanko int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
2379b692df1SIgor Mitsyanko const struct cfg80211_ap_settings *s)
23898f44cb0SIgor Mitsyanko {
23998f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
24017011da0SIgor Mitsyanko struct qlink_cmd_start_ap *cmd;
2418b5f4aa7SIgor Mitsyanko struct qlink_auth_encr *aen;
24298f44cb0SIgor Mitsyanko int ret;
24398f44cb0SIgor Mitsyanko int i;
244ecad3b0bSVeerendranath Jakkam int n;
24598f44cb0SIgor Mitsyanko
24617011da0SIgor Mitsyanko if (!qtnf_cmd_start_ap_can_fit(vif, s))
24717011da0SIgor Mitsyanko return -E2BIG;
24817011da0SIgor Mitsyanko
24998f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
25017011da0SIgor Mitsyanko QLINK_CMD_START_AP,
2518b5f4aa7SIgor Mitsyanko sizeof(*cmd));
252c93fe71cSSergey Matyukevich if (!cmd_skb)
25398f44cb0SIgor Mitsyanko return -ENOMEM;
25498f44cb0SIgor Mitsyanko
25517011da0SIgor Mitsyanko cmd = (struct qlink_cmd_start_ap *)cmd_skb->data;
2568b5f4aa7SIgor Mitsyanko cmd->dtim_period = s->dtim_period;
2578b5f4aa7SIgor Mitsyanko cmd->beacon_interval = cpu_to_le16(s->beacon_interval);
2588b5f4aa7SIgor Mitsyanko cmd->hidden_ssid = qlink_hidden_ssid_nl2q(s->hidden_ssid);
2598b5f4aa7SIgor Mitsyanko cmd->inactivity_timeout = cpu_to_le16(s->inactivity_timeout);
2608b5f4aa7SIgor Mitsyanko cmd->smps_mode = s->smps_mode;
2618b5f4aa7SIgor Mitsyanko cmd->p2p_ctwindow = s->p2p_ctwindow;
2628b5f4aa7SIgor Mitsyanko cmd->p2p_opp_ps = s->p2p_opp_ps;
2638b5f4aa7SIgor Mitsyanko cmd->pbss = s->pbss;
2648b5f4aa7SIgor Mitsyanko cmd->ht_required = s->ht_required;
2658b5f4aa7SIgor Mitsyanko cmd->vht_required = s->vht_required;
266ed7791d9SMikhail Karpenko cmd->twt_responder = s->twt_responder;
267ed7791d9SMikhail Karpenko if (s->he_obss_pd.enable) {
268ed7791d9SMikhail Karpenko cmd->sr_params.sr_control |= QLINK_SR_SRG_INFORMATION_PRESENT;
269ed7791d9SMikhail Karpenko cmd->sr_params.srg_obss_pd_min_offset =
270ed7791d9SMikhail Karpenko s->he_obss_pd.min_offset;
271ed7791d9SMikhail Karpenko cmd->sr_params.srg_obss_pd_max_offset =
272ed7791d9SMikhail Karpenko s->he_obss_pd.max_offset;
273ed7791d9SMikhail Karpenko }
27498f44cb0SIgor Mitsyanko
2758b5f4aa7SIgor Mitsyanko aen = &cmd->aen;
2768b5f4aa7SIgor Mitsyanko aen->auth_type = s->auth_type;
2778b5f4aa7SIgor Mitsyanko aen->privacy = !!s->privacy;
2788b5f4aa7SIgor Mitsyanko aen->wpa_versions = cpu_to_le32(s->crypto.wpa_versions);
2798b5f4aa7SIgor Mitsyanko aen->cipher_group = cpu_to_le32(s->crypto.cipher_group);
2808b5f4aa7SIgor Mitsyanko aen->n_ciphers_pairwise = cpu_to_le32(s->crypto.n_ciphers_pairwise);
28198f44cb0SIgor Mitsyanko for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++)
2828b5f4aa7SIgor Mitsyanko aen->ciphers_pairwise[i] =
2839b692df1SIgor Mitsyanko cpu_to_le32(s->crypto.ciphers_pairwise[i]);
284ecad3b0bSVeerendranath Jakkam n = min(QLINK_MAX_NR_AKM_SUITES, s->crypto.n_akm_suites);
285ecad3b0bSVeerendranath Jakkam aen->n_akm_suites = cpu_to_le32(n);
286ecad3b0bSVeerendranath Jakkam for (i = 0; i < n; i++)
2878b5f4aa7SIgor Mitsyanko aen->akm_suites[i] = cpu_to_le32(s->crypto.akm_suites[i]);
2888b5f4aa7SIgor Mitsyanko aen->control_port = s->crypto.control_port;
2898b5f4aa7SIgor Mitsyanko aen->control_port_no_encrypt = s->crypto.control_port_no_encrypt;
2908b5f4aa7SIgor Mitsyanko aen->control_port_ethertype =
2919b692df1SIgor Mitsyanko cpu_to_le16(be16_to_cpu(s->crypto.control_port_ethertype));
29298f44cb0SIgor Mitsyanko
293f99201cbSIgor Mitsyanko if (s->ssid && s->ssid_len > 0 && s->ssid_len <= IEEE80211_MAX_SSID_LEN)
294f99201cbSIgor Mitsyanko qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, s->ssid,
295f99201cbSIgor Mitsyanko s->ssid_len);
296f99201cbSIgor Mitsyanko
297f99201cbSIgor Mitsyanko if (cfg80211_chandef_valid(&s->chandef)) {
298f99201cbSIgor Mitsyanko struct qlink_tlv_chandef *chtlv =
299f99201cbSIgor Mitsyanko (struct qlink_tlv_chandef *)skb_put(cmd_skb,
300f99201cbSIgor Mitsyanko sizeof(*chtlv));
301f99201cbSIgor Mitsyanko
302f99201cbSIgor Mitsyanko chtlv->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANDEF);
303f99201cbSIgor Mitsyanko chtlv->hdr.len = cpu_to_le16(sizeof(*chtlv) -
304f99201cbSIgor Mitsyanko sizeof(chtlv->hdr));
3055bf374abSSergey Matyukevich qlink_chandef_cfg2q(&s->chandef, &chtlv->chdef);
306f99201cbSIgor Mitsyanko }
307f99201cbSIgor Mitsyanko
30817011da0SIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_BEACON_HEAD,
30917011da0SIgor Mitsyanko s->beacon.head, s->beacon.head_len);
31017011da0SIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_BEACON_TAIL,
31117011da0SIgor Mitsyanko s->beacon.tail, s->beacon.tail_len);
31217011da0SIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_BEACON_IES,
31317011da0SIgor Mitsyanko s->beacon.beacon_ies, s->beacon.beacon_ies_len);
31417011da0SIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_PROBE_RESP,
31517011da0SIgor Mitsyanko s->beacon.probe_resp, s->beacon.probe_resp_len);
31617011da0SIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_PROBE_RESP_IES,
31717011da0SIgor Mitsyanko s->beacon.proberesp_ies,
31817011da0SIgor Mitsyanko s->beacon.proberesp_ies_len);
31917011da0SIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_ASSOC_RESP,
32017011da0SIgor Mitsyanko s->beacon.assocresp_ies,
32117011da0SIgor Mitsyanko s->beacon.assocresp_ies_len);
32217011da0SIgor Mitsyanko
323a3945f43SIgor Mitsyanko if (s->ht_cap) {
324a3945f43SIgor Mitsyanko struct qlink_tlv_hdr *tlv = (struct qlink_tlv_hdr *)
3258b0b5f1bSIgor Mitsyanko skb_put(cmd_skb, sizeof(*tlv) +
3268b0b5f1bSIgor Mitsyanko round_up(sizeof(*s->ht_cap), QLINK_ALIGN));
327a3945f43SIgor Mitsyanko
328a3945f43SIgor Mitsyanko tlv->type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
329a3945f43SIgor Mitsyanko tlv->len = cpu_to_le16(sizeof(*s->ht_cap));
330a3945f43SIgor Mitsyanko memcpy(tlv->val, s->ht_cap, sizeof(*s->ht_cap));
331a3945f43SIgor Mitsyanko }
332a3945f43SIgor Mitsyanko
333a3945f43SIgor Mitsyanko if (s->vht_cap) {
334a3945f43SIgor Mitsyanko struct qlink_tlv_hdr *tlv = (struct qlink_tlv_hdr *)
335a3945f43SIgor Mitsyanko skb_put(cmd_skb, sizeof(*tlv) + sizeof(*s->vht_cap));
336a3945f43SIgor Mitsyanko
337a3945f43SIgor Mitsyanko tlv->type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
338a3945f43SIgor Mitsyanko tlv->len = cpu_to_le16(sizeof(*s->vht_cap));
339a3945f43SIgor Mitsyanko memcpy(tlv->val, s->vht_cap, sizeof(*s->vht_cap));
340a3945f43SIgor Mitsyanko }
341a3945f43SIgor Mitsyanko
342df0af4c7SMikhail Karpenko if (s->he_cap)
343df0af4c7SMikhail Karpenko qtnf_cmd_tlv_ie_ext_add(cmd_skb, WLAN_EID_EXT_HE_CAPABILITY,
344df0af4c7SMikhail Karpenko s->he_cap, sizeof(*s->he_cap));
345df0af4c7SMikhail Karpenko
346f1398fd2SVasily Ulyanov if (s->acl) {
34795336d4cSGustavo A. R. Silva size_t acl_size = struct_size(s->acl, mac_addrs,
34895336d4cSGustavo A. R. Silva s->acl->n_acl_entries);
349f1398fd2SVasily Ulyanov struct qlink_tlv_hdr *tlv =
3508b0b5f1bSIgor Mitsyanko skb_put(cmd_skb,
3518b0b5f1bSIgor Mitsyanko sizeof(*tlv) + round_up(acl_size, QLINK_ALIGN));
352f1398fd2SVasily Ulyanov
353f1398fd2SVasily Ulyanov tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA);
354f1398fd2SVasily Ulyanov tlv->len = cpu_to_le16(acl_size);
355f1398fd2SVasily Ulyanov qlink_acl_data_cfg2q(s->acl, (struct qlink_acl_data *)tlv->val);
356f1398fd2SVasily Ulyanov }
357f1398fd2SVasily Ulyanov
3588b5f4aa7SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
359c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
360c6ed298fSSergey Matyukevich if (ret)
36198f44cb0SIgor Mitsyanko goto out;
36298f44cb0SIgor Mitsyanko
36317011da0SIgor Mitsyanko netif_carrier_on(vif->netdev);
36417011da0SIgor Mitsyanko
36598f44cb0SIgor Mitsyanko out:
36698f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
367c6ed298fSSergey Matyukevich
36898f44cb0SIgor Mitsyanko return ret;
36998f44cb0SIgor Mitsyanko }
37098f44cb0SIgor Mitsyanko
qtnf_cmd_send_stop_ap(struct qtnf_vif * vif)37198f44cb0SIgor Mitsyanko int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif)
37298f44cb0SIgor Mitsyanko {
37398f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
37498f44cb0SIgor Mitsyanko int ret;
37598f44cb0SIgor Mitsyanko
37698f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
37798f44cb0SIgor Mitsyanko QLINK_CMD_STOP_AP,
37898f44cb0SIgor Mitsyanko sizeof(struct qlink_cmd));
379c93fe71cSSergey Matyukevich if (!cmd_skb)
38098f44cb0SIgor Mitsyanko return -ENOMEM;
38198f44cb0SIgor Mitsyanko
38298f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
383c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
38498f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
385c6ed298fSSergey Matyukevich
38698f44cb0SIgor Mitsyanko return ret;
38798f44cb0SIgor Mitsyanko }
38898f44cb0SIgor Mitsyanko
qtnf_cmd_send_register_mgmt(struct qtnf_vif * vif,u16 frame_type,bool reg)38998f44cb0SIgor Mitsyanko int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)
39098f44cb0SIgor Mitsyanko {
39198f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
39298f44cb0SIgor Mitsyanko struct qlink_cmd_mgmt_frame_register *cmd;
39398f44cb0SIgor Mitsyanko int ret;
39498f44cb0SIgor Mitsyanko
39598f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
39698f44cb0SIgor Mitsyanko QLINK_CMD_REGISTER_MGMT,
39798f44cb0SIgor Mitsyanko sizeof(*cmd));
398c93fe71cSSergey Matyukevich if (!cmd_skb)
39998f44cb0SIgor Mitsyanko return -ENOMEM;
40098f44cb0SIgor Mitsyanko
40198f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
40298f44cb0SIgor Mitsyanko
40398f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_mgmt_frame_register *)cmd_skb->data;
40498f44cb0SIgor Mitsyanko cmd->frame_type = cpu_to_le16(frame_type);
40598f44cb0SIgor Mitsyanko cmd->do_register = reg;
40698f44cb0SIgor Mitsyanko
407c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
40898f44cb0SIgor Mitsyanko
40998f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
410c6ed298fSSergey Matyukevich
41198f44cb0SIgor Mitsyanko return ret;
41298f44cb0SIgor Mitsyanko }
41398f44cb0SIgor Mitsyanko
qtnf_cmd_send_frame(struct qtnf_vif * vif,u32 cookie,u16 flags,u16 freq,const u8 * buf,size_t len)414bc70732fSIgor Mitsyanko int qtnf_cmd_send_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
41598f44cb0SIgor Mitsyanko u16 freq, const u8 *buf, size_t len)
41698f44cb0SIgor Mitsyanko {
41798f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
418bc70732fSIgor Mitsyanko struct qlink_cmd_frame_tx *cmd;
41998f44cb0SIgor Mitsyanko int ret;
42098f44cb0SIgor Mitsyanko
42198f44cb0SIgor Mitsyanko if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) {
42298f44cb0SIgor Mitsyanko pr_warn("VIF%u.%u: frame is too big: %zu\n", vif->mac->macid,
42398f44cb0SIgor Mitsyanko vif->vifid, len);
42498f44cb0SIgor Mitsyanko return -E2BIG;
42598f44cb0SIgor Mitsyanko }
42698f44cb0SIgor Mitsyanko
42798f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
428bc70732fSIgor Mitsyanko QLINK_CMD_SEND_FRAME,
42998f44cb0SIgor Mitsyanko sizeof(*cmd));
430c93fe71cSSergey Matyukevich if (!cmd_skb)
43198f44cb0SIgor Mitsyanko return -ENOMEM;
43298f44cb0SIgor Mitsyanko
43398f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
43498f44cb0SIgor Mitsyanko
435bc70732fSIgor Mitsyanko cmd = (struct qlink_cmd_frame_tx *)cmd_skb->data;
43698f44cb0SIgor Mitsyanko cmd->cookie = cpu_to_le32(cookie);
43798f44cb0SIgor Mitsyanko cmd->freq = cpu_to_le16(freq);
43898f44cb0SIgor Mitsyanko cmd->flags = cpu_to_le16(flags);
43998f44cb0SIgor Mitsyanko
44098f44cb0SIgor Mitsyanko if (len && buf)
44198f44cb0SIgor Mitsyanko qtnf_cmd_skb_put_buffer(cmd_skb, buf, len);
44298f44cb0SIgor Mitsyanko
443c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
44498f44cb0SIgor Mitsyanko
44598f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
446c6ed298fSSergey Matyukevich
44798f44cb0SIgor Mitsyanko return ret;
44898f44cb0SIgor Mitsyanko }
44998f44cb0SIgor Mitsyanko
qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif * vif,u8 frame_type,const u8 * buf,size_t len)45098f44cb0SIgor Mitsyanko int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,
45198f44cb0SIgor Mitsyanko const u8 *buf, size_t len)
45298f44cb0SIgor Mitsyanko {
45398f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
45498f44cb0SIgor Mitsyanko int ret;
45598f44cb0SIgor Mitsyanko
4564d1f0fabSIgor Mitsyanko if (len > QTNF_MAX_CMD_BUF_SIZE) {
45798f44cb0SIgor Mitsyanko pr_warn("VIF%u.%u: %u frame is too big: %zu\n", vif->mac->macid,
45898f44cb0SIgor Mitsyanko vif->vifid, frame_type, len);
45998f44cb0SIgor Mitsyanko return -E2BIG;
46098f44cb0SIgor Mitsyanko }
46198f44cb0SIgor Mitsyanko
46298f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
46398f44cb0SIgor Mitsyanko QLINK_CMD_MGMT_SET_APPIE,
4644d1f0fabSIgor Mitsyanko sizeof(struct qlink_cmd));
465c93fe71cSSergey Matyukevich if (!cmd_skb)
46698f44cb0SIgor Mitsyanko return -ENOMEM;
46798f44cb0SIgor Mitsyanko
4684d1f0fabSIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len);
4694d1f0fabSIgor Mitsyanko
47098f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
471c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
47298f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
473c6ed298fSSergey Matyukevich
47498f44cb0SIgor Mitsyanko return ret;
47598f44cb0SIgor Mitsyanko }
47698f44cb0SIgor Mitsyanko
47798f44cb0SIgor Mitsyanko static void
qtnf_sta_info_parse_rate(struct rate_info * rate_dst,const struct qlink_sta_info_rate * rate_src)47898f44cb0SIgor Mitsyanko qtnf_sta_info_parse_rate(struct rate_info *rate_dst,
47998f44cb0SIgor Mitsyanko const struct qlink_sta_info_rate *rate_src)
48098f44cb0SIgor Mitsyanko {
48198f44cb0SIgor Mitsyanko rate_dst->legacy = get_unaligned_le16(&rate_src->rate) * 10;
48298f44cb0SIgor Mitsyanko
48398f44cb0SIgor Mitsyanko rate_dst->mcs = rate_src->mcs;
48498f44cb0SIgor Mitsyanko rate_dst->nss = rate_src->nss;
48598f44cb0SIgor Mitsyanko rate_dst->flags = 0;
48698f44cb0SIgor Mitsyanko
48798f44cb0SIgor Mitsyanko switch (rate_src->bw) {
4884d2a7a1cSIgor Mitsyanko case QLINK_CHAN_WIDTH_5:
48998f44cb0SIgor Mitsyanko rate_dst->bw = RATE_INFO_BW_5;
49098f44cb0SIgor Mitsyanko break;
4914d2a7a1cSIgor Mitsyanko case QLINK_CHAN_WIDTH_10:
49298f44cb0SIgor Mitsyanko rate_dst->bw = RATE_INFO_BW_10;
49398f44cb0SIgor Mitsyanko break;
4944d2a7a1cSIgor Mitsyanko case QLINK_CHAN_WIDTH_20:
4954d2a7a1cSIgor Mitsyanko case QLINK_CHAN_WIDTH_20_NOHT:
49698f44cb0SIgor Mitsyanko rate_dst->bw = RATE_INFO_BW_20;
49798f44cb0SIgor Mitsyanko break;
4984d2a7a1cSIgor Mitsyanko case QLINK_CHAN_WIDTH_40:
49998f44cb0SIgor Mitsyanko rate_dst->bw = RATE_INFO_BW_40;
50098f44cb0SIgor Mitsyanko break;
5014d2a7a1cSIgor Mitsyanko case QLINK_CHAN_WIDTH_80:
50298f44cb0SIgor Mitsyanko rate_dst->bw = RATE_INFO_BW_80;
50398f44cb0SIgor Mitsyanko break;
5044d2a7a1cSIgor Mitsyanko case QLINK_CHAN_WIDTH_160:
50598f44cb0SIgor Mitsyanko rate_dst->bw = RATE_INFO_BW_160;
50698f44cb0SIgor Mitsyanko break;
50798f44cb0SIgor Mitsyanko default:
50898f44cb0SIgor Mitsyanko rate_dst->bw = 0;
50998f44cb0SIgor Mitsyanko break;
51098f44cb0SIgor Mitsyanko }
51198f44cb0SIgor Mitsyanko
51298f44cb0SIgor Mitsyanko if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_HT_MCS)
51398f44cb0SIgor Mitsyanko rate_dst->flags |= RATE_INFO_FLAGS_MCS;
51498f44cb0SIgor Mitsyanko else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS)
51598f44cb0SIgor Mitsyanko rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS;
516b73f0aacSSergey Matyukevich else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_HE_MCS)
517b73f0aacSSergey Matyukevich rate_dst->flags |= RATE_INFO_FLAGS_HE_MCS;
518d5657b70SSergey Matyukevich
519d5657b70SSergey Matyukevich if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_SHORT_GI)
520d5657b70SSergey Matyukevich rate_dst->flags |= RATE_INFO_FLAGS_SHORT_GI;
52198f44cb0SIgor Mitsyanko }
52298f44cb0SIgor Mitsyanko
52398f44cb0SIgor Mitsyanko static void
qtnf_sta_info_parse_flags(struct nl80211_sta_flag_update * dst,const struct qlink_sta_info_state * src)52498f44cb0SIgor Mitsyanko qtnf_sta_info_parse_flags(struct nl80211_sta_flag_update *dst,
52598f44cb0SIgor Mitsyanko const struct qlink_sta_info_state *src)
52698f44cb0SIgor Mitsyanko {
52798f44cb0SIgor Mitsyanko u32 mask, value;
52898f44cb0SIgor Mitsyanko
52998f44cb0SIgor Mitsyanko dst->mask = 0;
53098f44cb0SIgor Mitsyanko dst->set = 0;
53198f44cb0SIgor Mitsyanko
53298f44cb0SIgor Mitsyanko mask = le32_to_cpu(src->mask);
53398f44cb0SIgor Mitsyanko value = le32_to_cpu(src->value);
53498f44cb0SIgor Mitsyanko
53598f44cb0SIgor Mitsyanko if (mask & QLINK_STA_FLAG_AUTHORIZED) {
53698f44cb0SIgor Mitsyanko dst->mask |= BIT(NL80211_STA_FLAG_AUTHORIZED);
53798f44cb0SIgor Mitsyanko if (value & QLINK_STA_FLAG_AUTHORIZED)
53898f44cb0SIgor Mitsyanko dst->set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
53998f44cb0SIgor Mitsyanko }
54098f44cb0SIgor Mitsyanko
54198f44cb0SIgor Mitsyanko if (mask & QLINK_STA_FLAG_SHORT_PREAMBLE) {
54298f44cb0SIgor Mitsyanko dst->mask |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
54398f44cb0SIgor Mitsyanko if (value & QLINK_STA_FLAG_SHORT_PREAMBLE)
54498f44cb0SIgor Mitsyanko dst->set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
54598f44cb0SIgor Mitsyanko }
54698f44cb0SIgor Mitsyanko
54798f44cb0SIgor Mitsyanko if (mask & QLINK_STA_FLAG_WME) {
54898f44cb0SIgor Mitsyanko dst->mask |= BIT(NL80211_STA_FLAG_WME);
54998f44cb0SIgor Mitsyanko if (value & QLINK_STA_FLAG_WME)
55098f44cb0SIgor Mitsyanko dst->set |= BIT(NL80211_STA_FLAG_WME);
55198f44cb0SIgor Mitsyanko }
55298f44cb0SIgor Mitsyanko
55398f44cb0SIgor Mitsyanko if (mask & QLINK_STA_FLAG_MFP) {
55498f44cb0SIgor Mitsyanko dst->mask |= BIT(NL80211_STA_FLAG_MFP);
55598f44cb0SIgor Mitsyanko if (value & QLINK_STA_FLAG_MFP)
55698f44cb0SIgor Mitsyanko dst->set |= BIT(NL80211_STA_FLAG_MFP);
55798f44cb0SIgor Mitsyanko }
55898f44cb0SIgor Mitsyanko
55998f44cb0SIgor Mitsyanko if (mask & QLINK_STA_FLAG_AUTHENTICATED) {
56098f44cb0SIgor Mitsyanko dst->mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
56198f44cb0SIgor Mitsyanko if (value & QLINK_STA_FLAG_AUTHENTICATED)
56298f44cb0SIgor Mitsyanko dst->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
56398f44cb0SIgor Mitsyanko }
56498f44cb0SIgor Mitsyanko
56598f44cb0SIgor Mitsyanko if (mask & QLINK_STA_FLAG_TDLS_PEER) {
56698f44cb0SIgor Mitsyanko dst->mask |= BIT(NL80211_STA_FLAG_TDLS_PEER);
56798f44cb0SIgor Mitsyanko if (value & QLINK_STA_FLAG_TDLS_PEER)
56898f44cb0SIgor Mitsyanko dst->set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
56998f44cb0SIgor Mitsyanko }
57098f44cb0SIgor Mitsyanko
57198f44cb0SIgor Mitsyanko if (mask & QLINK_STA_FLAG_ASSOCIATED) {
57298f44cb0SIgor Mitsyanko dst->mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
57398f44cb0SIgor Mitsyanko if (value & QLINK_STA_FLAG_ASSOCIATED)
57498f44cb0SIgor Mitsyanko dst->set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
57598f44cb0SIgor Mitsyanko }
57698f44cb0SIgor Mitsyanko }
57798f44cb0SIgor Mitsyanko
57898f44cb0SIgor Mitsyanko static void
qtnf_cmd_sta_info_parse(struct station_info * sinfo,const u8 * data,size_t resp_size)5798b0b5f1bSIgor Mitsyanko qtnf_cmd_sta_info_parse(struct station_info *sinfo, const u8 *data,
5804d2a7a1cSIgor Mitsyanko size_t resp_size)
58198f44cb0SIgor Mitsyanko {
5828b0b5f1bSIgor Mitsyanko const struct qlink_tlv_hdr *tlv;
5834d2a7a1cSIgor Mitsyanko const struct qlink_sta_stats *stats = NULL;
5844d2a7a1cSIgor Mitsyanko const u8 *map = NULL;
5854d2a7a1cSIgor Mitsyanko unsigned int map_len = 0;
5864d2a7a1cSIgor Mitsyanko unsigned int stats_len = 0;
5874d2a7a1cSIgor Mitsyanko u16 tlv_len;
58898f44cb0SIgor Mitsyanko
5894d2a7a1cSIgor Mitsyanko #define qtnf_sta_stat_avail(stat_name, bitn) \
5904d2a7a1cSIgor Mitsyanko (qtnf_utils_is_bit_set(map, bitn, map_len) && \
5914d2a7a1cSIgor Mitsyanko (offsetofend(struct qlink_sta_stats, stat_name) <= stats_len))
59298f44cb0SIgor Mitsyanko
5938b0b5f1bSIgor Mitsyanko qlink_for_each_tlv(tlv, data, resp_size) {
5944d2a7a1cSIgor Mitsyanko tlv_len = le16_to_cpu(tlv->len);
59598f44cb0SIgor Mitsyanko
5964d2a7a1cSIgor Mitsyanko switch (le16_to_cpu(tlv->type)) {
597310cd5ddSIgor Mitsyanko case QTN_TLV_ID_BITMAP:
5984d2a7a1cSIgor Mitsyanko map_len = tlv_len;
5994d2a7a1cSIgor Mitsyanko map = tlv->val;
60098f44cb0SIgor Mitsyanko break;
6014d2a7a1cSIgor Mitsyanko case QTN_TLV_ID_STA_STATS:
6024d2a7a1cSIgor Mitsyanko stats_len = tlv_len;
6034d2a7a1cSIgor Mitsyanko stats = (const struct qlink_sta_stats *)tlv->val;
60498f44cb0SIgor Mitsyanko break;
60598f44cb0SIgor Mitsyanko default:
60698f44cb0SIgor Mitsyanko break;
60798f44cb0SIgor Mitsyanko }
6088b0b5f1bSIgor Mitsyanko }
6094d2a7a1cSIgor Mitsyanko
6108b0b5f1bSIgor Mitsyanko if (!qlink_tlv_parsing_ok(tlv, data, resp_size)) {
6118b0b5f1bSIgor Mitsyanko pr_err("Malformed TLV buffer\n");
6128b0b5f1bSIgor Mitsyanko return;
61398f44cb0SIgor Mitsyanko }
61498f44cb0SIgor Mitsyanko
6154d2a7a1cSIgor Mitsyanko if (!map || !stats)
6164d2a7a1cSIgor Mitsyanko return;
6174d2a7a1cSIgor Mitsyanko
6184d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(inactive_time, QLINK_STA_INFO_INACTIVE_TIME)) {
61922d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME);
6204d2a7a1cSIgor Mitsyanko sinfo->inactive_time = le32_to_cpu(stats->inactive_time);
62198f44cb0SIgor Mitsyanko }
62298f44cb0SIgor Mitsyanko
6234d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(connected_time,
6244d2a7a1cSIgor Mitsyanko QLINK_STA_INFO_CONNECTED_TIME)) {
62522d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME);
6264d2a7a1cSIgor Mitsyanko sinfo->connected_time = le32_to_cpu(stats->connected_time);
6274d2a7a1cSIgor Mitsyanko }
6284d2a7a1cSIgor Mitsyanko
6294d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(signal, QLINK_STA_INFO_SIGNAL)) {
63022d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
6314d2a7a1cSIgor Mitsyanko sinfo->signal = stats->signal - QLINK_RSSI_OFFSET;
6324d2a7a1cSIgor Mitsyanko }
6334d2a7a1cSIgor Mitsyanko
6344d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(signal_avg, QLINK_STA_INFO_SIGNAL_AVG)) {
63522d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
6364d2a7a1cSIgor Mitsyanko sinfo->signal_avg = stats->signal_avg - QLINK_RSSI_OFFSET;
6374d2a7a1cSIgor Mitsyanko }
6384d2a7a1cSIgor Mitsyanko
6394d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(rxrate, QLINK_STA_INFO_RX_BITRATE)) {
64022d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
6414d2a7a1cSIgor Mitsyanko qtnf_sta_info_parse_rate(&sinfo->rxrate, &stats->rxrate);
6424d2a7a1cSIgor Mitsyanko }
6434d2a7a1cSIgor Mitsyanko
6444d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(txrate, QLINK_STA_INFO_TX_BITRATE)) {
64522d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
6464d2a7a1cSIgor Mitsyanko qtnf_sta_info_parse_rate(&sinfo->txrate, &stats->txrate);
6474d2a7a1cSIgor Mitsyanko }
6484d2a7a1cSIgor Mitsyanko
6494d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(sta_flags, QLINK_STA_INFO_STA_FLAGS)) {
65022d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_STA_FLAGS);
6514d2a7a1cSIgor Mitsyanko qtnf_sta_info_parse_flags(&sinfo->sta_flags, &stats->sta_flags);
6524d2a7a1cSIgor Mitsyanko }
6534d2a7a1cSIgor Mitsyanko
6544d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES)) {
65522d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES);
6564d2a7a1cSIgor Mitsyanko sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes);
6574d2a7a1cSIgor Mitsyanko }
6584d2a7a1cSIgor Mitsyanko
6594d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES)) {
66022d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES);
6614d2a7a1cSIgor Mitsyanko sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes);
6624d2a7a1cSIgor Mitsyanko }
6634d2a7a1cSIgor Mitsyanko
6644d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES64)) {
66522d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64);
6664d2a7a1cSIgor Mitsyanko sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes);
6674d2a7a1cSIgor Mitsyanko }
6684d2a7a1cSIgor Mitsyanko
6694d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES64)) {
67022d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
6714d2a7a1cSIgor Mitsyanko sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes);
6724d2a7a1cSIgor Mitsyanko }
6734d2a7a1cSIgor Mitsyanko
6744d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(rx_packets, QLINK_STA_INFO_RX_PACKETS)) {
67522d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);
6764d2a7a1cSIgor Mitsyanko sinfo->rx_packets = le32_to_cpu(stats->rx_packets);
6774d2a7a1cSIgor Mitsyanko }
6784d2a7a1cSIgor Mitsyanko
6794d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(tx_packets, QLINK_STA_INFO_TX_PACKETS)) {
68022d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
6814d2a7a1cSIgor Mitsyanko sinfo->tx_packets = le32_to_cpu(stats->tx_packets);
6824d2a7a1cSIgor Mitsyanko }
6834d2a7a1cSIgor Mitsyanko
6844d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(rx_beacon, QLINK_STA_INFO_BEACON_RX)) {
68522d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX);
6864d2a7a1cSIgor Mitsyanko sinfo->rx_beacon = le64_to_cpu(stats->rx_beacon);
6874d2a7a1cSIgor Mitsyanko }
6884d2a7a1cSIgor Mitsyanko
6894d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(rx_dropped_misc, QLINK_STA_INFO_RX_DROP_MISC)) {
69022d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC);
6914d2a7a1cSIgor Mitsyanko sinfo->rx_dropped_misc = le32_to_cpu(stats->rx_dropped_misc);
6924d2a7a1cSIgor Mitsyanko }
6934d2a7a1cSIgor Mitsyanko
6944d2a7a1cSIgor Mitsyanko if (qtnf_sta_stat_avail(tx_failed, QLINK_STA_INFO_TX_FAILED)) {
69522d0d2faSOmer Efrat sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
6964d2a7a1cSIgor Mitsyanko sinfo->tx_failed = le32_to_cpu(stats->tx_failed);
6974d2a7a1cSIgor Mitsyanko }
6984d2a7a1cSIgor Mitsyanko
6994d2a7a1cSIgor Mitsyanko #undef qtnf_sta_stat_avail
70098f44cb0SIgor Mitsyanko }
70198f44cb0SIgor Mitsyanko
qtnf_cmd_get_sta_info(struct qtnf_vif * vif,const u8 * sta_mac,struct station_info * sinfo)70298f44cb0SIgor Mitsyanko int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
70398f44cb0SIgor Mitsyanko struct station_info *sinfo)
70498f44cb0SIgor Mitsyanko {
70598f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb, *resp_skb = NULL;
70698f44cb0SIgor Mitsyanko struct qlink_cmd_get_sta_info *cmd;
70798f44cb0SIgor Mitsyanko const struct qlink_resp_get_sta_info *resp;
7081066bd19SSergey Matyukevich size_t var_resp_len = 0;
70998f44cb0SIgor Mitsyanko int ret = 0;
71098f44cb0SIgor Mitsyanko
71198f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
71298f44cb0SIgor Mitsyanko QLINK_CMD_GET_STA_INFO,
71398f44cb0SIgor Mitsyanko sizeof(*cmd));
714c93fe71cSSergey Matyukevich if (!cmd_skb)
71598f44cb0SIgor Mitsyanko return -ENOMEM;
71698f44cb0SIgor Mitsyanko
71798f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
71898f44cb0SIgor Mitsyanko
71998f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_get_sta_info *)cmd_skb->data;
72098f44cb0SIgor Mitsyanko ether_addr_copy(cmd->sta_addr, sta_mac);
72198f44cb0SIgor Mitsyanko
72298f44cb0SIgor Mitsyanko ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb,
723c6ed298fSSergey Matyukevich sizeof(*resp), &var_resp_len);
724c6ed298fSSergey Matyukevich if (ret)
72598f44cb0SIgor Mitsyanko goto out;
72698f44cb0SIgor Mitsyanko
72798f44cb0SIgor Mitsyanko resp = (const struct qlink_resp_get_sta_info *)resp_skb->data;
72898f44cb0SIgor Mitsyanko
729c6ed298fSSergey Matyukevich if (!ether_addr_equal(sta_mac, resp->sta_addr)) {
73098f44cb0SIgor Mitsyanko pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n",
73198f44cb0SIgor Mitsyanko vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac);
73298f44cb0SIgor Mitsyanko ret = -EINVAL;
73398f44cb0SIgor Mitsyanko goto out;
73498f44cb0SIgor Mitsyanko }
73598f44cb0SIgor Mitsyanko
7368b0b5f1bSIgor Mitsyanko qtnf_cmd_sta_info_parse(sinfo, resp->info, var_resp_len);
73798f44cb0SIgor Mitsyanko
73898f44cb0SIgor Mitsyanko out:
73998f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
74098f44cb0SIgor Mitsyanko consume_skb(resp_skb);
74198f44cb0SIgor Mitsyanko
74298f44cb0SIgor Mitsyanko return ret;
74398f44cb0SIgor Mitsyanko }
74498f44cb0SIgor Mitsyanko
qtnf_cmd_send_add_change_intf(struct qtnf_vif * vif,enum nl80211_iftype iftype,int use4addr,u8 * mac_addr,enum qlink_cmd_type cmd_type)74598f44cb0SIgor Mitsyanko static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif,
74698f44cb0SIgor Mitsyanko enum nl80211_iftype iftype,
747de624a35SSergey Matyukevich int use4addr,
74898f44cb0SIgor Mitsyanko u8 *mac_addr,
74998f44cb0SIgor Mitsyanko enum qlink_cmd_type cmd_type)
75098f44cb0SIgor Mitsyanko {
75198f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb, *resp_skb = NULL;
75298f44cb0SIgor Mitsyanko struct qlink_cmd_manage_intf *cmd;
75398f44cb0SIgor Mitsyanko const struct qlink_resp_manage_intf *resp;
75498f44cb0SIgor Mitsyanko int ret = 0;
75598f44cb0SIgor Mitsyanko
75698f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
75798f44cb0SIgor Mitsyanko cmd_type,
75898f44cb0SIgor Mitsyanko sizeof(*cmd));
759c93fe71cSSergey Matyukevich if (!cmd_skb)
76098f44cb0SIgor Mitsyanko return -ENOMEM;
76198f44cb0SIgor Mitsyanko
76298f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
76398f44cb0SIgor Mitsyanko
76498f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data;
765de624a35SSergey Matyukevich cmd->intf_info.use4addr = use4addr;
76698f44cb0SIgor Mitsyanko
76798f44cb0SIgor Mitsyanko switch (iftype) {
76898f44cb0SIgor Mitsyanko case NL80211_IFTYPE_AP:
76998f44cb0SIgor Mitsyanko cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP);
77098f44cb0SIgor Mitsyanko break;
77198f44cb0SIgor Mitsyanko case NL80211_IFTYPE_STATION:
77298f44cb0SIgor Mitsyanko cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION);
77398f44cb0SIgor Mitsyanko break;
77498f44cb0SIgor Mitsyanko default:
77598f44cb0SIgor Mitsyanko pr_err("VIF%u.%u: unsupported type %d\n", vif->mac->macid,
77698f44cb0SIgor Mitsyanko vif->vifid, iftype);
77798f44cb0SIgor Mitsyanko ret = -EINVAL;
77898f44cb0SIgor Mitsyanko goto out;
77998f44cb0SIgor Mitsyanko }
78098f44cb0SIgor Mitsyanko
78198f44cb0SIgor Mitsyanko if (mac_addr)
78298f44cb0SIgor Mitsyanko ether_addr_copy(cmd->intf_info.mac_addr, mac_addr);
78398f44cb0SIgor Mitsyanko else
78498f44cb0SIgor Mitsyanko eth_zero_addr(cmd->intf_info.mac_addr);
78598f44cb0SIgor Mitsyanko
78698f44cb0SIgor Mitsyanko ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb,
787c6ed298fSSergey Matyukevich sizeof(*resp), NULL);
788c6ed298fSSergey Matyukevich if (ret)
78998f44cb0SIgor Mitsyanko goto out;
79098f44cb0SIgor Mitsyanko
79198f44cb0SIgor Mitsyanko resp = (const struct qlink_resp_manage_intf *)resp_skb->data;
79298f44cb0SIgor Mitsyanko ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr);
79398f44cb0SIgor Mitsyanko
79498f44cb0SIgor Mitsyanko out:
79598f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
79698f44cb0SIgor Mitsyanko consume_skb(resp_skb);
79798f44cb0SIgor Mitsyanko
79898f44cb0SIgor Mitsyanko return ret;
79998f44cb0SIgor Mitsyanko }
80098f44cb0SIgor Mitsyanko
qtnf_cmd_send_add_intf(struct qtnf_vif * vif,enum nl80211_iftype iftype,int use4addr,u8 * mac_addr)801de624a35SSergey Matyukevich int qtnf_cmd_send_add_intf(struct qtnf_vif *vif, enum nl80211_iftype iftype,
802de624a35SSergey Matyukevich int use4addr, u8 *mac_addr)
80398f44cb0SIgor Mitsyanko {
804de624a35SSergey Matyukevich return qtnf_cmd_send_add_change_intf(vif, iftype, use4addr, mac_addr,
80598f44cb0SIgor Mitsyanko QLINK_CMD_ADD_INTF);
80698f44cb0SIgor Mitsyanko }
80798f44cb0SIgor Mitsyanko
qtnf_cmd_send_change_intf_type(struct qtnf_vif * vif,enum nl80211_iftype iftype,int use4addr,u8 * mac_addr)80898f44cb0SIgor Mitsyanko int qtnf_cmd_send_change_intf_type(struct qtnf_vif *vif,
809de624a35SSergey Matyukevich enum nl80211_iftype iftype,
810de624a35SSergey Matyukevich int use4addr,
811de624a35SSergey Matyukevich u8 *mac_addr)
81298f44cb0SIgor Mitsyanko {
81393eeab26SIgor Mitsyanko int ret;
81493eeab26SIgor Mitsyanko
81593eeab26SIgor Mitsyanko ret = qtnf_cmd_send_add_change_intf(vif, iftype, use4addr, mac_addr,
81698f44cb0SIgor Mitsyanko QLINK_CMD_CHANGE_INTF);
81793eeab26SIgor Mitsyanko
81893eeab26SIgor Mitsyanko /* Regulatory settings may be different for different interface types */
81993eeab26SIgor Mitsyanko if (ret == 0 && vif->wdev.iftype != iftype) {
82093eeab26SIgor Mitsyanko enum nl80211_band band;
82193eeab26SIgor Mitsyanko struct wiphy *wiphy = priv_to_wiphy(vif->mac);
82293eeab26SIgor Mitsyanko
82393eeab26SIgor Mitsyanko for (band = 0; band < NUM_NL80211_BANDS; ++band) {
82493eeab26SIgor Mitsyanko if (!wiphy->bands[band])
82593eeab26SIgor Mitsyanko continue;
82693eeab26SIgor Mitsyanko
82793eeab26SIgor Mitsyanko qtnf_cmd_band_info_get(vif->mac, wiphy->bands[band]);
82893eeab26SIgor Mitsyanko }
82993eeab26SIgor Mitsyanko }
83093eeab26SIgor Mitsyanko
83193eeab26SIgor Mitsyanko return ret;
83298f44cb0SIgor Mitsyanko }
83398f44cb0SIgor Mitsyanko
qtnf_cmd_send_del_intf(struct qtnf_vif * vif)83498f44cb0SIgor Mitsyanko int qtnf_cmd_send_del_intf(struct qtnf_vif *vif)
83598f44cb0SIgor Mitsyanko {
83698f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
83798f44cb0SIgor Mitsyanko struct qlink_cmd_manage_intf *cmd;
83898f44cb0SIgor Mitsyanko int ret = 0;
83998f44cb0SIgor Mitsyanko
84098f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
84198f44cb0SIgor Mitsyanko QLINK_CMD_DEL_INTF,
84298f44cb0SIgor Mitsyanko sizeof(*cmd));
843c93fe71cSSergey Matyukevich if (!cmd_skb)
84498f44cb0SIgor Mitsyanko return -ENOMEM;
84598f44cb0SIgor Mitsyanko
84698f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
84798f44cb0SIgor Mitsyanko
84898f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_manage_intf *)cmd_skb->data;
84998f44cb0SIgor Mitsyanko
85098f44cb0SIgor Mitsyanko switch (vif->wdev.iftype) {
85198f44cb0SIgor Mitsyanko case NL80211_IFTYPE_AP:
85298f44cb0SIgor Mitsyanko cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_AP);
85398f44cb0SIgor Mitsyanko break;
85498f44cb0SIgor Mitsyanko case NL80211_IFTYPE_STATION:
85598f44cb0SIgor Mitsyanko cmd->intf_info.if_type = cpu_to_le16(QLINK_IFTYPE_STATION);
85698f44cb0SIgor Mitsyanko break;
85798f44cb0SIgor Mitsyanko default:
85898f44cb0SIgor Mitsyanko pr_warn("VIF%u.%u: unsupported iftype %d\n", vif->mac->macid,
85998f44cb0SIgor Mitsyanko vif->vifid, vif->wdev.iftype);
86063f69820SColin Ian King dev_kfree_skb(cmd_skb);
86198f44cb0SIgor Mitsyanko ret = -EINVAL;
86298f44cb0SIgor Mitsyanko goto out;
86398f44cb0SIgor Mitsyanko }
86498f44cb0SIgor Mitsyanko
86598f44cb0SIgor Mitsyanko eth_zero_addr(cmd->intf_info.mac_addr);
86698f44cb0SIgor Mitsyanko
867c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
868c6ed298fSSergey Matyukevich if (ret)
86998f44cb0SIgor Mitsyanko goto out;
87098f44cb0SIgor Mitsyanko
87198f44cb0SIgor Mitsyanko out:
87298f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
87398f44cb0SIgor Mitsyanko return ret;
87498f44cb0SIgor Mitsyanko }
87598f44cb0SIgor Mitsyanko
87698f44cb0SIgor Mitsyanko static int
qtnf_cmd_resp_proc_hw_info(struct qtnf_bus * bus,const struct qlink_resp_get_hw_info * resp,size_t info_len)87798f44cb0SIgor Mitsyanko qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
8784dd07d2bSSergey Matyukevich const struct qlink_resp_get_hw_info *resp,
8794dd07d2bSSergey Matyukevich size_t info_len)
88098f44cb0SIgor Mitsyanko {
88198f44cb0SIgor Mitsyanko struct qtnf_hw_info *hwinfo = &bus->hw_info;
8824dd07d2bSSergey Matyukevich const struct qlink_tlv_hdr *tlv;
8835ec5b532SVasily Ulyanov const char *bld_name = NULL;
8845ec5b532SVasily Ulyanov const char *bld_rev = NULL;
8855ec5b532SVasily Ulyanov const char *bld_type = NULL;
8865ec5b532SVasily Ulyanov const char *bld_label = NULL;
8875ec5b532SVasily Ulyanov u32 bld_tmstamp = 0;
8885ec5b532SVasily Ulyanov u32 plat_id = 0;
8895ec5b532SVasily Ulyanov const char *hw_id = NULL;
8905ec5b532SVasily Ulyanov const char *calibration_ver = NULL;
8915ec5b532SVasily Ulyanov const char *uboot_ver = NULL;
8925ec5b532SVasily Ulyanov u32 hw_ver = 0;
8934dd07d2bSSergey Matyukevich u16 tlv_type;
894310cd5ddSIgor Mitsyanko u16 tlv_len;
89598f44cb0SIgor Mitsyanko
89698f44cb0SIgor Mitsyanko hwinfo->num_mac = resp->num_mac;
89798f44cb0SIgor Mitsyanko hwinfo->mac_bitmap = resp->mac_bitmap;
89898f44cb0SIgor Mitsyanko hwinfo->fw_ver = le32_to_cpu(resp->fw_ver);
89998f44cb0SIgor Mitsyanko hwinfo->total_tx_chain = resp->total_tx_chain;
90098f44cb0SIgor Mitsyanko hwinfo->total_rx_chain = resp->total_rx_chain;
9014dd07d2bSSergey Matyukevich
9025ec5b532SVasily Ulyanov bld_tmstamp = le32_to_cpu(resp->bld_tmstamp);
9035ec5b532SVasily Ulyanov plat_id = le32_to_cpu(resp->plat_id);
9045ec5b532SVasily Ulyanov hw_ver = le32_to_cpu(resp->hw_ver);
9055ec5b532SVasily Ulyanov
9068b0b5f1bSIgor Mitsyanko qlink_for_each_tlv(tlv, resp->info, info_len) {
9074dd07d2bSSergey Matyukevich tlv_type = le16_to_cpu(tlv->type);
908310cd5ddSIgor Mitsyanko tlv_len = le16_to_cpu(tlv->len);
9094dd07d2bSSergey Matyukevich
9104dd07d2bSSergey Matyukevich switch (tlv_type) {
9115ec5b532SVasily Ulyanov case QTN_TLV_ID_BUILD_NAME:
9125ec5b532SVasily Ulyanov bld_name = (const void *)tlv->val;
9135ec5b532SVasily Ulyanov break;
9145ec5b532SVasily Ulyanov case QTN_TLV_ID_BUILD_REV:
9155ec5b532SVasily Ulyanov bld_rev = (const void *)tlv->val;
9165ec5b532SVasily Ulyanov break;
9175ec5b532SVasily Ulyanov case QTN_TLV_ID_BUILD_TYPE:
9185ec5b532SVasily Ulyanov bld_type = (const void *)tlv->val;
9195ec5b532SVasily Ulyanov break;
9205ec5b532SVasily Ulyanov case QTN_TLV_ID_BUILD_LABEL:
9215ec5b532SVasily Ulyanov bld_label = (const void *)tlv->val;
9225ec5b532SVasily Ulyanov break;
9235ec5b532SVasily Ulyanov case QTN_TLV_ID_HW_ID:
9245ec5b532SVasily Ulyanov hw_id = (const void *)tlv->val;
9255ec5b532SVasily Ulyanov break;
9265ec5b532SVasily Ulyanov case QTN_TLV_ID_CALIBRATION_VER:
9275ec5b532SVasily Ulyanov calibration_ver = (const void *)tlv->val;
9285ec5b532SVasily Ulyanov break;
9295ec5b532SVasily Ulyanov case QTN_TLV_ID_UBOOT_VER:
9305ec5b532SVasily Ulyanov uboot_ver = (const void *)tlv->val;
9315ec5b532SVasily Ulyanov break;
932310cd5ddSIgor Mitsyanko case QTN_TLV_ID_BITMAP:
933310cd5ddSIgor Mitsyanko memcpy(hwinfo->hw_capab, tlv->val,
934310cd5ddSIgor Mitsyanko min(sizeof(hwinfo->hw_capab), (size_t)tlv_len));
935310cd5ddSIgor Mitsyanko break;
9364dd07d2bSSergey Matyukevich default:
9374dd07d2bSSergey Matyukevich break;
9384dd07d2bSSergey Matyukevich }
9398b0b5f1bSIgor Mitsyanko }
9404dd07d2bSSergey Matyukevich
9418b0b5f1bSIgor Mitsyanko if (!qlink_tlv_parsing_ok(tlv, resp->info, info_len)) {
9428b0b5f1bSIgor Mitsyanko pr_err("Malformed TLV buffer\n");
9438b0b5f1bSIgor Mitsyanko return -EINVAL;
9444dd07d2bSSergey Matyukevich }
9454dd07d2bSSergey Matyukevich
946a3ebb033SIgor Mitsyanko pr_info("\nBuild name: %s\n"
947a3ebb033SIgor Mitsyanko "Build revision: %s\n"
948a3ebb033SIgor Mitsyanko "Build type: %s\n"
949a3ebb033SIgor Mitsyanko "Build label: %s\n"
950a3ebb033SIgor Mitsyanko "Build timestamp: %lu\n"
951a3ebb033SIgor Mitsyanko "Platform ID: %lu\n"
952a3ebb033SIgor Mitsyanko "Hardware ID: %s\n"
953a3ebb033SIgor Mitsyanko "Calibration version: %s\n"
954a3ebb033SIgor Mitsyanko "U-Boot version: %s\n"
955a3ebb033SIgor Mitsyanko "Hardware version: 0x%08x\n"
956a3ebb033SIgor Mitsyanko "Qlink ver: %u.%u\n"
957a3ebb033SIgor Mitsyanko "MACs map: %#x\n"
958a3ebb033SIgor Mitsyanko "Chains Rx-Tx: %ux%u\n"
959a3ebb033SIgor Mitsyanko "FW version: 0x%x\n",
9605ec5b532SVasily Ulyanov bld_name, bld_rev, bld_type, bld_label,
9615ec5b532SVasily Ulyanov (unsigned long)bld_tmstamp,
9625ec5b532SVasily Ulyanov (unsigned long)plat_id,
963a3ebb033SIgor Mitsyanko hw_id, calibration_ver, uboot_ver, hw_ver,
964a3ebb033SIgor Mitsyanko QLINK_VER_MAJOR(bus->hw_info.ql_proto_ver),
965a3ebb033SIgor Mitsyanko QLINK_VER_MINOR(bus->hw_info.ql_proto_ver),
966a3ebb033SIgor Mitsyanko hwinfo->mac_bitmap,
967a3ebb033SIgor Mitsyanko hwinfo->total_rx_chain, hwinfo->total_tx_chain,
968a3ebb033SIgor Mitsyanko hwinfo->fw_ver);
9695ec5b532SVasily Ulyanov
970bf99f11dSWolfram Sang strscpy(hwinfo->fw_version, bld_label, sizeof(hwinfo->fw_version));
9710b419d01SVasily Ulyanov hwinfo->hw_version = hw_ver;
9720b419d01SVasily Ulyanov
97398f44cb0SIgor Mitsyanko return 0;
97498f44cb0SIgor Mitsyanko }
97598f44cb0SIgor Mitsyanko
97628b91884SSergey Matyukevich static void
qtnf_parse_wowlan_info(struct qtnf_wmac * mac,const struct qlink_wowlan_capab_data * wowlan)97728b91884SSergey Matyukevich qtnf_parse_wowlan_info(struct qtnf_wmac *mac,
97828b91884SSergey Matyukevich const struct qlink_wowlan_capab_data *wowlan)
97928b91884SSergey Matyukevich {
98028b91884SSergey Matyukevich struct qtnf_mac_info *mac_info = &mac->macinfo;
98128b91884SSergey Matyukevich const struct qlink_wowlan_support *data1;
98228b91884SSergey Matyukevich struct wiphy_wowlan_support *supp;
98328b91884SSergey Matyukevich
98428b91884SSergey Matyukevich supp = kzalloc(sizeof(*supp), GFP_KERNEL);
98528b91884SSergey Matyukevich if (!supp)
98628b91884SSergey Matyukevich return;
98728b91884SSergey Matyukevich
98828b91884SSergey Matyukevich switch (le16_to_cpu(wowlan->version)) {
98928b91884SSergey Matyukevich case 0x1:
99028b91884SSergey Matyukevich data1 = (struct qlink_wowlan_support *)wowlan->data;
99128b91884SSergey Matyukevich
99228b91884SSergey Matyukevich supp->flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT;
99328b91884SSergey Matyukevich supp->n_patterns = le32_to_cpu(data1->n_patterns);
99428b91884SSergey Matyukevich supp->pattern_max_len = le32_to_cpu(data1->pattern_max_len);
99528b91884SSergey Matyukevich supp->pattern_min_len = le32_to_cpu(data1->pattern_min_len);
99628b91884SSergey Matyukevich
99728b91884SSergey Matyukevich mac_info->wowlan = supp;
99828b91884SSergey Matyukevich break;
99928b91884SSergey Matyukevich default:
100028b91884SSergey Matyukevich pr_warn("MAC%u: unsupported WoWLAN version 0x%x\n",
100128b91884SSergey Matyukevich mac->macid, le16_to_cpu(wowlan->version));
100228b91884SSergey Matyukevich kfree(supp);
100328b91884SSergey Matyukevich break;
100428b91884SSergey Matyukevich }
100528b91884SSergey Matyukevich }
100628b91884SSergey Matyukevich
1007c698bce0SIgor Mitsyanko static int
qtnf_parse_variable_mac_info(struct qtnf_wmac * mac,const struct qlink_resp_get_mac_info * resp,size_t tlv_buf_size)1008c698bce0SIgor Mitsyanko qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
1009c698bce0SIgor Mitsyanko const struct qlink_resp_get_mac_info *resp,
1010c698bce0SIgor Mitsyanko size_t tlv_buf_size)
101198f44cb0SIgor Mitsyanko {
1012bc5db734SIgor Mitsyanko struct ieee80211_iface_combination *comb = mac->macinfo.if_comb;
1013537faf26SSergey Matyukevich size_t n_comb = 0;
1014537faf26SSergey Matyukevich struct ieee80211_iface_limit *limits;
1015537faf26SSergey Matyukevich const struct qlink_iface_limit_record *rec;
1016537faf26SSergey Matyukevich const struct qlink_iface_limit *lim;
101728b91884SSergey Matyukevich const struct qlink_wowlan_capab_data *wowlan;
1018537faf26SSergey Matyukevich u16 rec_len;
1019537faf26SSergey Matyukevich u16 tlv_type;
1020537faf26SSergey Matyukevich u16 tlv_value_len;
102198f44cb0SIgor Mitsyanko const struct qlink_tlv_hdr *tlv;
10229cbd5999SVasily Ulyanov u8 *ext_capa = NULL;
10239cbd5999SVasily Ulyanov u8 *ext_capa_mask = NULL;
10249cbd5999SVasily Ulyanov u8 ext_capa_len = 0;
10259cbd5999SVasily Ulyanov u8 ext_capa_mask_len = 0;
1026537faf26SSergey Matyukevich int i = 0;
1027c698bce0SIgor Mitsyanko struct ieee80211_reg_rule *rule;
1028c698bce0SIgor Mitsyanko unsigned int rule_idx = 0;
1029c698bce0SIgor Mitsyanko const struct qlink_tlv_reg_rule *tlv_rule;
1030c698bce0SIgor Mitsyanko
1031c698bce0SIgor Mitsyanko if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES))
1032c698bce0SIgor Mitsyanko return -E2BIG;
1033c698bce0SIgor Mitsyanko
10349a1ace64SGustavo A. R. Silva mac->rd = kzalloc(struct_size(mac->rd, reg_rules, resp->n_reg_rules),
10359a1ace64SGustavo A. R. Silva GFP_KERNEL);
1036c698bce0SIgor Mitsyanko if (!mac->rd)
1037c698bce0SIgor Mitsyanko return -ENOMEM;
1038c698bce0SIgor Mitsyanko
1039c698bce0SIgor Mitsyanko mac->rd->n_reg_rules = resp->n_reg_rules;
1040c698bce0SIgor Mitsyanko mac->rd->alpha2[0] = resp->alpha2[0];
1041c698bce0SIgor Mitsyanko mac->rd->alpha2[1] = resp->alpha2[1];
1042c698bce0SIgor Mitsyanko
1043c698bce0SIgor Mitsyanko switch (resp->dfs_region) {
1044c698bce0SIgor Mitsyanko case QLINK_DFS_FCC:
1045c698bce0SIgor Mitsyanko mac->rd->dfs_region = NL80211_DFS_FCC;
1046c698bce0SIgor Mitsyanko break;
1047c698bce0SIgor Mitsyanko case QLINK_DFS_ETSI:
1048c698bce0SIgor Mitsyanko mac->rd->dfs_region = NL80211_DFS_ETSI;
1049c698bce0SIgor Mitsyanko break;
1050c698bce0SIgor Mitsyanko case QLINK_DFS_JP:
1051c698bce0SIgor Mitsyanko mac->rd->dfs_region = NL80211_DFS_JP;
1052c698bce0SIgor Mitsyanko break;
1053c698bce0SIgor Mitsyanko case QLINK_DFS_UNSET:
1054c698bce0SIgor Mitsyanko default:
1055c698bce0SIgor Mitsyanko mac->rd->dfs_region = NL80211_DFS_UNSET;
1056c698bce0SIgor Mitsyanko break;
1057c698bce0SIgor Mitsyanko }
105898f44cb0SIgor Mitsyanko
10598b0b5f1bSIgor Mitsyanko qlink_for_each_tlv(tlv, resp->var_info, tlv_buf_size) {
106098f44cb0SIgor Mitsyanko tlv_type = le16_to_cpu(tlv->type);
106198f44cb0SIgor Mitsyanko tlv_value_len = le16_to_cpu(tlv->len);
106298f44cb0SIgor Mitsyanko
106398f44cb0SIgor Mitsyanko switch (tlv_type) {
106498f44cb0SIgor Mitsyanko case QTN_TLV_ID_IFACE_LIMIT:
1065537faf26SSergey Matyukevich if (unlikely(!comb)) {
1066537faf26SSergey Matyukevich pr_warn("MAC%u: no combinations advertised\n",
106798f44cb0SIgor Mitsyanko mac->macid);
106898f44cb0SIgor Mitsyanko return -EINVAL;
106998f44cb0SIgor Mitsyanko }
107098f44cb0SIgor Mitsyanko
1071537faf26SSergey Matyukevich if (n_comb >= mac->macinfo.n_if_comb) {
1072537faf26SSergey Matyukevich pr_warn("MAC%u: combinations count exceeded\n",
107398f44cb0SIgor Mitsyanko mac->macid);
1074537faf26SSergey Matyukevich n_comb++;
1075537faf26SSergey Matyukevich break;
1076537faf26SSergey Matyukevich }
1077537faf26SSergey Matyukevich
1078537faf26SSergey Matyukevich rec = (void *)tlv->val;
1079537faf26SSergey Matyukevich rec_len = sizeof(*rec) + rec->n_limits * sizeof(*lim);
1080537faf26SSergey Matyukevich
1081537faf26SSergey Matyukevich if (unlikely(tlv_value_len != rec_len)) {
1082537faf26SSergey Matyukevich pr_warn("MAC%u: record %zu size mismatch\n",
1083537faf26SSergey Matyukevich mac->macid, n_comb);
108498f44cb0SIgor Mitsyanko return -EINVAL;
108598f44cb0SIgor Mitsyanko }
108698f44cb0SIgor Mitsyanko
10876396bb22SKees Cook limits = kcalloc(rec->n_limits, sizeof(*limits),
1088537faf26SSergey Matyukevich GFP_KERNEL);
1089537faf26SSergey Matyukevich if (!limits)
1090537faf26SSergey Matyukevich return -ENOMEM;
109141c8fa0cSSergey Matyukevich
1092537faf26SSergey Matyukevich comb[n_comb].num_different_channels =
1093537faf26SSergey Matyukevich rec->num_different_channels;
1094537faf26SSergey Matyukevich comb[n_comb].max_interfaces =
1095537faf26SSergey Matyukevich le16_to_cpu(rec->max_interfaces);
1096537faf26SSergey Matyukevich comb[n_comb].n_limits = rec->n_limits;
1097537faf26SSergey Matyukevich comb[n_comb].limits = limits;
109898f44cb0SIgor Mitsyanko
1099537faf26SSergey Matyukevich for (i = 0; i < rec->n_limits; i++) {
1100537faf26SSergey Matyukevich lim = &rec->limits[i];
1101537faf26SSergey Matyukevich limits[i].max = le16_to_cpu(lim->max_num);
1102537faf26SSergey Matyukevich limits[i].types =
1103537faf26SSergey Matyukevich qlink_iface_type_to_nl_mask(le16_to_cpu(lim->type));
1104537faf26SSergey Matyukevich pr_debug("MAC%u: comb[%zu]: MAX:%u TYPES:%.4X\n",
1105537faf26SSergey Matyukevich mac->macid, n_comb,
1106537faf26SSergey Matyukevich limits[i].max, limits[i].types);
1107537faf26SSergey Matyukevich }
110898f44cb0SIgor Mitsyanko
1109537faf26SSergey Matyukevich n_comb++;
111098f44cb0SIgor Mitsyanko break;
11119cbd5999SVasily Ulyanov case WLAN_EID_EXT_CAPABILITY:
11129cbd5999SVasily Ulyanov if (unlikely(tlv_value_len > U8_MAX))
11139cbd5999SVasily Ulyanov return -EINVAL;
11149cbd5999SVasily Ulyanov ext_capa = (u8 *)tlv->val;
11159cbd5999SVasily Ulyanov ext_capa_len = tlv_value_len;
11169cbd5999SVasily Ulyanov break;
11179cbd5999SVasily Ulyanov case QTN_TLV_ID_EXT_CAPABILITY_MASK:
11189cbd5999SVasily Ulyanov if (unlikely(tlv_value_len > U8_MAX))
11199cbd5999SVasily Ulyanov return -EINVAL;
11209cbd5999SVasily Ulyanov ext_capa_mask = (u8 *)tlv->val;
11219cbd5999SVasily Ulyanov ext_capa_mask_len = tlv_value_len;
11229cbd5999SVasily Ulyanov break;
112328b91884SSergey Matyukevich case QTN_TLV_ID_WOWLAN_CAPAB:
112428b91884SSergey Matyukevich if (tlv_value_len < sizeof(*wowlan))
112528b91884SSergey Matyukevich return -EINVAL;
112628b91884SSergey Matyukevich
112728b91884SSergey Matyukevich wowlan = (void *)tlv->val;
112828b91884SSergey Matyukevich if (!le16_to_cpu(wowlan->len)) {
112928b91884SSergey Matyukevich pr_warn("MAC%u: skip empty WoWLAN data\n",
113028b91884SSergey Matyukevich mac->macid);
113128b91884SSergey Matyukevich break;
113228b91884SSergey Matyukevich }
113328b91884SSergey Matyukevich
113428b91884SSergey Matyukevich rec_len = sizeof(*wowlan) + le16_to_cpu(wowlan->len);
113528b91884SSergey Matyukevich if (unlikely(tlv_value_len != rec_len)) {
113628b91884SSergey Matyukevich pr_warn("MAC%u: WoWLAN data size mismatch\n",
113728b91884SSergey Matyukevich mac->macid);
113828b91884SSergey Matyukevich return -EINVAL;
113928b91884SSergey Matyukevich }
114028b91884SSergey Matyukevich
114128b91884SSergey Matyukevich kfree(mac->macinfo.wowlan);
114228b91884SSergey Matyukevich mac->macinfo.wowlan = NULL;
114328b91884SSergey Matyukevich qtnf_parse_wowlan_info(mac, wowlan);
114428b91884SSergey Matyukevich break;
1145c698bce0SIgor Mitsyanko case QTN_TLV_ID_REG_RULE:
1146c698bce0SIgor Mitsyanko if (rule_idx >= resp->n_reg_rules) {
1147c698bce0SIgor Mitsyanko pr_warn("unexpected number of rules: %u\n",
1148c698bce0SIgor Mitsyanko resp->n_reg_rules);
1149c698bce0SIgor Mitsyanko return -EINVAL;
1150c698bce0SIgor Mitsyanko }
1151c698bce0SIgor Mitsyanko
1152c698bce0SIgor Mitsyanko if (tlv_value_len != sizeof(*tlv_rule) - sizeof(*tlv)) {
1153c698bce0SIgor Mitsyanko pr_warn("malformed TLV 0x%.2X; LEN: %u\n",
1154c698bce0SIgor Mitsyanko tlv_type, tlv_value_len);
1155c698bce0SIgor Mitsyanko return -EINVAL;
1156c698bce0SIgor Mitsyanko }
1157c698bce0SIgor Mitsyanko
1158c698bce0SIgor Mitsyanko tlv_rule = (const struct qlink_tlv_reg_rule *)tlv;
1159c698bce0SIgor Mitsyanko rule = &mac->rd->reg_rules[rule_idx++];
1160c698bce0SIgor Mitsyanko qlink_utils_regrule_q2nl(rule, tlv_rule);
1161c698bce0SIgor Mitsyanko break;
116298f44cb0SIgor Mitsyanko default:
116328b91884SSergey Matyukevich pr_warn("MAC%u: unknown TLV type %u\n",
116428b91884SSergey Matyukevich mac->macid, tlv_type);
116598f44cb0SIgor Mitsyanko break;
116698f44cb0SIgor Mitsyanko }
116798f44cb0SIgor Mitsyanko }
116898f44cb0SIgor Mitsyanko
11698b0b5f1bSIgor Mitsyanko if (!qlink_tlv_parsing_ok(tlv, resp->var_info, tlv_buf_size)) {
11708b0b5f1bSIgor Mitsyanko pr_err("Malformed TLV buffer\n");
117198f44cb0SIgor Mitsyanko return -EINVAL;
117298f44cb0SIgor Mitsyanko }
117398f44cb0SIgor Mitsyanko
1174537faf26SSergey Matyukevich if (mac->macinfo.n_if_comb != n_comb) {
117598f44cb0SIgor Mitsyanko pr_err("MAC%u: combination mismatch: reported=%zu parsed=%zu\n",
1176537faf26SSergey Matyukevich mac->macid, mac->macinfo.n_if_comb, n_comb);
117798f44cb0SIgor Mitsyanko return -EINVAL;
117898f44cb0SIgor Mitsyanko }
117998f44cb0SIgor Mitsyanko
11809cbd5999SVasily Ulyanov if (ext_capa_len != ext_capa_mask_len) {
11819cbd5999SVasily Ulyanov pr_err("MAC%u: ext_capa/_mask lengths mismatch: %u != %u\n",
11829cbd5999SVasily Ulyanov mac->macid, ext_capa_len, ext_capa_mask_len);
11839cbd5999SVasily Ulyanov return -EINVAL;
11849cbd5999SVasily Ulyanov }
11859cbd5999SVasily Ulyanov
1186c698bce0SIgor Mitsyanko if (rule_idx != resp->n_reg_rules) {
1187c698bce0SIgor Mitsyanko pr_warn("unexpected number of rules: expected %u got %u\n",
1188c698bce0SIgor Mitsyanko resp->n_reg_rules, rule_idx);
1189c698bce0SIgor Mitsyanko return -EINVAL;
1190c698bce0SIgor Mitsyanko }
1191c698bce0SIgor Mitsyanko
11929cbd5999SVasily Ulyanov if (ext_capa_len > 0) {
11939cbd5999SVasily Ulyanov ext_capa = kmemdup(ext_capa, ext_capa_len, GFP_KERNEL);
11949cbd5999SVasily Ulyanov if (!ext_capa)
11959cbd5999SVasily Ulyanov return -ENOMEM;
11969cbd5999SVasily Ulyanov
11979cbd5999SVasily Ulyanov ext_capa_mask =
11989cbd5999SVasily Ulyanov kmemdup(ext_capa_mask, ext_capa_mask_len, GFP_KERNEL);
11999cbd5999SVasily Ulyanov if (!ext_capa_mask) {
12009cbd5999SVasily Ulyanov kfree(ext_capa);
12019cbd5999SVasily Ulyanov return -ENOMEM;
12029cbd5999SVasily Ulyanov }
12039cbd5999SVasily Ulyanov } else {
12049cbd5999SVasily Ulyanov ext_capa = NULL;
12059cbd5999SVasily Ulyanov ext_capa_mask = NULL;
12069cbd5999SVasily Ulyanov }
12079cbd5999SVasily Ulyanov
1208ab1c64a1SSergey Matyukevich qtnf_mac_ext_caps_free(mac);
12099cbd5999SVasily Ulyanov mac->macinfo.extended_capabilities = ext_capa;
12109cbd5999SVasily Ulyanov mac->macinfo.extended_capabilities_mask = ext_capa_mask;
12119cbd5999SVasily Ulyanov mac->macinfo.extended_capabilities_len = ext_capa_len;
12129cbd5999SVasily Ulyanov
121398f44cb0SIgor Mitsyanko return 0;
121498f44cb0SIgor Mitsyanko }
121598f44cb0SIgor Mitsyanko
1216bc5db734SIgor Mitsyanko static int
qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac * mac,const struct qlink_resp_get_mac_info * resp_info)121798f44cb0SIgor Mitsyanko qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac,
121898f44cb0SIgor Mitsyanko const struct qlink_resp_get_mac_info *resp_info)
121998f44cb0SIgor Mitsyanko {
122098f44cb0SIgor Mitsyanko struct qtnf_mac_info *mac_info;
122198f44cb0SIgor Mitsyanko struct qtnf_vif *vif;
122298f44cb0SIgor Mitsyanko
1223bc5db734SIgor Mitsyanko qtnf_mac_iface_comb_free(mac);
1224bc5db734SIgor Mitsyanko
122598f44cb0SIgor Mitsyanko mac_info = &mac->macinfo;
122698f44cb0SIgor Mitsyanko
122798f44cb0SIgor Mitsyanko mac_info->bands_cap = resp_info->bands_cap;
12284e14e76cSIgor Mitsyanko ether_addr_copy(mac->macaddr, resp_info->dev_mac);
122998f44cb0SIgor Mitsyanko
123098f44cb0SIgor Mitsyanko vif = qtnf_mac_get_base_vif(mac);
123198f44cb0SIgor Mitsyanko if (vif)
123298f44cb0SIgor Mitsyanko ether_addr_copy(vif->mac_addr, mac->macaddr);
123398f44cb0SIgor Mitsyanko else
123498f44cb0SIgor Mitsyanko pr_err("could not get valid base vif\n");
123598f44cb0SIgor Mitsyanko
123698f44cb0SIgor Mitsyanko mac_info->num_tx_chain = resp_info->num_tx_chain;
123798f44cb0SIgor Mitsyanko mac_info->num_rx_chain = resp_info->num_rx_chain;
123898f44cb0SIgor Mitsyanko
123998f44cb0SIgor Mitsyanko mac_info->max_ap_assoc_sta = le16_to_cpu(resp_info->max_ap_assoc_sta);
124098f44cb0SIgor Mitsyanko mac_info->radar_detect_widths =
124198f44cb0SIgor Mitsyanko qlink_chan_width_mask_to_nl(le16_to_cpu(
124298f44cb0SIgor Mitsyanko resp_info->radar_detect_widths));
1243e70cf22bSIgor Mitsyanko mac_info->max_acl_mac_addrs = le16_to_cpu(resp_info->max_acl_mac_addrs);
1244e70cf22bSIgor Mitsyanko mac_info->frag_thr = le32_to_cpu(resp_info->frag_threshold);
1245e70cf22bSIgor Mitsyanko mac_info->rts_thr = le32_to_cpu(resp_info->rts_threshold);
1246e70cf22bSIgor Mitsyanko mac_info->sretry_limit = resp_info->retry_short;
1247e70cf22bSIgor Mitsyanko mac_info->lretry_limit = resp_info->retry_long;
1248e70cf22bSIgor Mitsyanko mac_info->coverage_class = resp_info->coverage_class;
12490d18a9c0SIgor Mitsyanko mac_info->max_scan_ssids = resp_info->max_scan_ssids;
125098f44cb0SIgor Mitsyanko
1251d42df85fSIgor Mitsyanko memcpy(&mac_info->ht_cap_mod_mask, &resp_info->ht_cap_mod_mask,
1252d42df85fSIgor Mitsyanko sizeof(mac_info->ht_cap_mod_mask));
1253d42df85fSIgor Mitsyanko memcpy(&mac_info->vht_cap_mod_mask, &resp_info->vht_cap_mod_mask,
1254d42df85fSIgor Mitsyanko sizeof(mac_info->vht_cap_mod_mask));
1255bc5db734SIgor Mitsyanko
1256bc5db734SIgor Mitsyanko mac_info->n_if_comb = resp_info->n_iface_combinations;
1257bc5db734SIgor Mitsyanko mac_info->if_comb = kcalloc(mac->macinfo.n_if_comb,
1258bc5db734SIgor Mitsyanko sizeof(*mac->macinfo.if_comb),
1259bc5db734SIgor Mitsyanko GFP_KERNEL);
1260bc5db734SIgor Mitsyanko
1261bc5db734SIgor Mitsyanko if (!mac->macinfo.if_comb)
1262bc5db734SIgor Mitsyanko return -ENOMEM;
1263bc5db734SIgor Mitsyanko
1264bc5db734SIgor Mitsyanko return 0;
126598f44cb0SIgor Mitsyanko }
126698f44cb0SIgor Mitsyanko
qtnf_cmd_resp_band_fill_htcap(const u8 * info,struct ieee80211_sta_ht_cap * bcap)1267e294cbfdSIgor Mitsyanko static void qtnf_cmd_resp_band_fill_htcap(const u8 *info,
1268e294cbfdSIgor Mitsyanko struct ieee80211_sta_ht_cap *bcap)
1269e294cbfdSIgor Mitsyanko {
1270e294cbfdSIgor Mitsyanko const struct ieee80211_ht_cap *ht_cap =
1271e294cbfdSIgor Mitsyanko (const struct ieee80211_ht_cap *)info;
1272e294cbfdSIgor Mitsyanko
1273e294cbfdSIgor Mitsyanko bcap->ht_supported = true;
1274e294cbfdSIgor Mitsyanko bcap->cap = le16_to_cpu(ht_cap->cap_info);
1275e294cbfdSIgor Mitsyanko bcap->ampdu_factor =
1276e294cbfdSIgor Mitsyanko ht_cap->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
1277e294cbfdSIgor Mitsyanko bcap->ampdu_density =
1278e294cbfdSIgor Mitsyanko (ht_cap->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >>
1279e294cbfdSIgor Mitsyanko IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
1280e294cbfdSIgor Mitsyanko memcpy(&bcap->mcs, &ht_cap->mcs, sizeof(bcap->mcs));
1281e294cbfdSIgor Mitsyanko }
1282e294cbfdSIgor Mitsyanko
qtnf_cmd_resp_band_fill_vhtcap(const u8 * info,struct ieee80211_sta_vht_cap * bcap)1283e294cbfdSIgor Mitsyanko static void qtnf_cmd_resp_band_fill_vhtcap(const u8 *info,
1284e294cbfdSIgor Mitsyanko struct ieee80211_sta_vht_cap *bcap)
1285e294cbfdSIgor Mitsyanko {
1286e294cbfdSIgor Mitsyanko const struct ieee80211_vht_cap *vht_cap =
1287e294cbfdSIgor Mitsyanko (const struct ieee80211_vht_cap *)info;
1288e294cbfdSIgor Mitsyanko
1289e294cbfdSIgor Mitsyanko bcap->vht_supported = true;
1290e294cbfdSIgor Mitsyanko bcap->cap = le32_to_cpu(vht_cap->vht_cap_info);
1291e294cbfdSIgor Mitsyanko memcpy(&bcap->vht_mcs, &vht_cap->supp_mcs, sizeof(bcap->vht_mcs));
1292e294cbfdSIgor Mitsyanko }
1293e294cbfdSIgor Mitsyanko
qtnf_cmd_conv_iftype(struct ieee80211_sband_iftype_data * iftype_data,const struct qlink_sband_iftype_data * qlink_data)1294df0af4c7SMikhail Karpenko static void qtnf_cmd_conv_iftype(struct ieee80211_sband_iftype_data
1295df0af4c7SMikhail Karpenko *iftype_data,
1296df0af4c7SMikhail Karpenko const struct qlink_sband_iftype_data
1297df0af4c7SMikhail Karpenko *qlink_data)
1298df0af4c7SMikhail Karpenko {
1299df0af4c7SMikhail Karpenko iftype_data->types_mask = le16_to_cpu(qlink_data->types_mask);
1300df0af4c7SMikhail Karpenko
1301df0af4c7SMikhail Karpenko iftype_data->he_cap.has_he = true;
1302df0af4c7SMikhail Karpenko memcpy(&iftype_data->he_cap.he_cap_elem, &qlink_data->he_cap_elem,
1303df0af4c7SMikhail Karpenko sizeof(qlink_data->he_cap_elem));
1304df0af4c7SMikhail Karpenko memcpy(iftype_data->he_cap.ppe_thres, qlink_data->ppe_thres,
1305df0af4c7SMikhail Karpenko ARRAY_SIZE(qlink_data->ppe_thres));
1306df0af4c7SMikhail Karpenko
1307df0af4c7SMikhail Karpenko iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80 =
1308df0af4c7SMikhail Karpenko qlink_data->he_mcs_nss_supp.rx_mcs_80;
1309df0af4c7SMikhail Karpenko iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80 =
1310df0af4c7SMikhail Karpenko qlink_data->he_mcs_nss_supp.tx_mcs_80;
1311df0af4c7SMikhail Karpenko iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_160 =
1312df0af4c7SMikhail Karpenko qlink_data->he_mcs_nss_supp.rx_mcs_160;
1313df0af4c7SMikhail Karpenko iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160 =
1314df0af4c7SMikhail Karpenko qlink_data->he_mcs_nss_supp.tx_mcs_160;
1315df0af4c7SMikhail Karpenko iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80p80 =
1316df0af4c7SMikhail Karpenko qlink_data->he_mcs_nss_supp.rx_mcs_80p80;
1317df0af4c7SMikhail Karpenko iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80p80 =
1318df0af4c7SMikhail Karpenko qlink_data->he_mcs_nss_supp.tx_mcs_80p80;
1319df0af4c7SMikhail Karpenko }
1320df0af4c7SMikhail Karpenko
qtnf_cmd_band_fill_iftype(const u8 * data,struct ieee80211_supported_band * band)1321df0af4c7SMikhail Karpenko static int qtnf_cmd_band_fill_iftype(const u8 *data,
1322df0af4c7SMikhail Karpenko struct ieee80211_supported_band *band)
1323df0af4c7SMikhail Karpenko {
1324df0af4c7SMikhail Karpenko unsigned int i;
1325df0af4c7SMikhail Karpenko struct ieee80211_sband_iftype_data *iftype_data;
1326df0af4c7SMikhail Karpenko const struct qlink_tlv_iftype_data *tlv =
1327df0af4c7SMikhail Karpenko (const struct qlink_tlv_iftype_data *)data;
1328*84e9e210SJacob Keller size_t payload_len;
1329*84e9e210SJacob Keller
1330*84e9e210SJacob Keller payload_len = struct_size(tlv, iftype_data, tlv->n_iftype_data);
1331*84e9e210SJacob Keller payload_len = size_sub(payload_len, sizeof(struct qlink_tlv_hdr));
1332df0af4c7SMikhail Karpenko
1333df0af4c7SMikhail Karpenko if (tlv->hdr.len != cpu_to_le16(payload_len)) {
1334df0af4c7SMikhail Karpenko pr_err("bad IFTYPE_DATA TLV len %u\n", tlv->hdr.len);
1335df0af4c7SMikhail Karpenko return -EINVAL;
1336df0af4c7SMikhail Karpenko }
1337df0af4c7SMikhail Karpenko
1338df0af4c7SMikhail Karpenko kfree(band->iftype_data);
1339df0af4c7SMikhail Karpenko band->iftype_data = NULL;
1340df0af4c7SMikhail Karpenko band->n_iftype_data = tlv->n_iftype_data;
1341df0af4c7SMikhail Karpenko if (band->n_iftype_data == 0)
1342df0af4c7SMikhail Karpenko return 0;
1343df0af4c7SMikhail Karpenko
1344df0af4c7SMikhail Karpenko iftype_data = kcalloc(band->n_iftype_data, sizeof(*iftype_data),
1345df0af4c7SMikhail Karpenko GFP_KERNEL);
1346df0af4c7SMikhail Karpenko if (!iftype_data) {
1347df0af4c7SMikhail Karpenko band->n_iftype_data = 0;
1348df0af4c7SMikhail Karpenko return -ENOMEM;
1349df0af4c7SMikhail Karpenko }
1350df0af4c7SMikhail Karpenko band->iftype_data = iftype_data;
1351df0af4c7SMikhail Karpenko
1352df0af4c7SMikhail Karpenko for (i = 0; i < band->n_iftype_data; i++)
1353df0af4c7SMikhail Karpenko qtnf_cmd_conv_iftype(iftype_data++, &tlv->iftype_data[i]);
1354df0af4c7SMikhail Karpenko
1355df0af4c7SMikhail Karpenko return 0;
1356df0af4c7SMikhail Karpenko }
1357df0af4c7SMikhail Karpenko
135898f44cb0SIgor Mitsyanko static int
qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band * band,struct qlink_resp_band_info_get * resp,size_t payload_len)1359e294cbfdSIgor Mitsyanko qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
1360e294cbfdSIgor Mitsyanko struct qlink_resp_band_info_get *resp,
136198f44cb0SIgor Mitsyanko size_t payload_len)
136298f44cb0SIgor Mitsyanko {
136398f44cb0SIgor Mitsyanko u16 tlv_type;
1364e294cbfdSIgor Mitsyanko size_t tlv_dlen;
136598f44cb0SIgor Mitsyanko const struct qlink_tlv_hdr *tlv;
13665bf374abSSergey Matyukevich const struct qlink_channel *qchan;
136798f44cb0SIgor Mitsyanko struct ieee80211_channel *chan;
136898f44cb0SIgor Mitsyanko unsigned int chidx = 0;
136998f44cb0SIgor Mitsyanko u32 qflags;
1370df0af4c7SMikhail Karpenko int ret = -EINVAL;
137198f44cb0SIgor Mitsyanko
1372e294cbfdSIgor Mitsyanko memset(&band->ht_cap, 0, sizeof(band->ht_cap));
1373e294cbfdSIgor Mitsyanko memset(&band->vht_cap, 0, sizeof(band->vht_cap));
1374e294cbfdSIgor Mitsyanko
13754dd07d2bSSergey Matyukevich if (band->channels) {
13764dd07d2bSSergey Matyukevich if (band->n_channels == resp->num_chans) {
13774dd07d2bSSergey Matyukevich memset(band->channels, 0,
13784dd07d2bSSergey Matyukevich sizeof(*band->channels) * band->n_channels);
13794dd07d2bSSergey Matyukevich } else {
138098f44cb0SIgor Mitsyanko kfree(band->channels);
13814dd07d2bSSergey Matyukevich band->n_channels = 0;
138298f44cb0SIgor Mitsyanko band->channels = NULL;
13834dd07d2bSSergey Matyukevich }
13844dd07d2bSSergey Matyukevich }
138598f44cb0SIgor Mitsyanko
138698f44cb0SIgor Mitsyanko band->n_channels = resp->num_chans;
138798f44cb0SIgor Mitsyanko if (band->n_channels == 0)
138898f44cb0SIgor Mitsyanko return 0;
138998f44cb0SIgor Mitsyanko
13904dd07d2bSSergey Matyukevich if (!band->channels)
13914dd07d2bSSergey Matyukevich band->channels = kcalloc(band->n_channels, sizeof(*chan),
13924dd07d2bSSergey Matyukevich GFP_KERNEL);
139398f44cb0SIgor Mitsyanko if (!band->channels) {
139498f44cb0SIgor Mitsyanko band->n_channels = 0;
139598f44cb0SIgor Mitsyanko return -ENOMEM;
139698f44cb0SIgor Mitsyanko }
139798f44cb0SIgor Mitsyanko
13988b0b5f1bSIgor Mitsyanko qlink_for_each_tlv(tlv, resp->info, payload_len) {
139998f44cb0SIgor Mitsyanko tlv_type = le16_to_cpu(tlv->type);
1400e294cbfdSIgor Mitsyanko tlv_dlen = le16_to_cpu(tlv->len);
140198f44cb0SIgor Mitsyanko
140298f44cb0SIgor Mitsyanko switch (tlv_type) {
140398f44cb0SIgor Mitsyanko case QTN_TLV_ID_CHANNEL:
14045bf374abSSergey Matyukevich if (unlikely(tlv_dlen != sizeof(*qchan))) {
140598f44cb0SIgor Mitsyanko pr_err("invalid channel TLV len %zu\n",
14068b0b5f1bSIgor Mitsyanko tlv_dlen);
140798f44cb0SIgor Mitsyanko goto error_ret;
140898f44cb0SIgor Mitsyanko }
140998f44cb0SIgor Mitsyanko
141098f44cb0SIgor Mitsyanko if (chidx == band->n_channels) {
141198f44cb0SIgor Mitsyanko pr_err("too many channel TLVs\n");
141298f44cb0SIgor Mitsyanko goto error_ret;
141398f44cb0SIgor Mitsyanko }
141498f44cb0SIgor Mitsyanko
14155bf374abSSergey Matyukevich qchan = (const struct qlink_channel *)tlv->val;
141698f44cb0SIgor Mitsyanko chan = &band->channels[chidx++];
141798f44cb0SIgor Mitsyanko qflags = le32_to_cpu(qchan->flags);
141898f44cb0SIgor Mitsyanko
141998f44cb0SIgor Mitsyanko chan->hw_value = le16_to_cpu(qchan->hw_value);
142098f44cb0SIgor Mitsyanko chan->band = band->band;
142198f44cb0SIgor Mitsyanko chan->center_freq = le16_to_cpu(qchan->center_freq);
142298f44cb0SIgor Mitsyanko chan->max_antenna_gain = (int)qchan->max_antenna_gain;
142398f44cb0SIgor Mitsyanko chan->max_power = (int)qchan->max_power;
142498f44cb0SIgor Mitsyanko chan->max_reg_power = (int)qchan->max_reg_power;
142598f44cb0SIgor Mitsyanko chan->beacon_found = qchan->beacon_found;
142698f44cb0SIgor Mitsyanko chan->dfs_cac_ms = le32_to_cpu(qchan->dfs_cac_ms);
142798f44cb0SIgor Mitsyanko chan->flags = 0;
142898f44cb0SIgor Mitsyanko
142998f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_DISABLED)
143098f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_DISABLED;
143198f44cb0SIgor Mitsyanko
143298f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_NO_IR)
143398f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_NO_IR;
143498f44cb0SIgor Mitsyanko
143598f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_NO_HT40PLUS)
143698f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_NO_HT40PLUS;
143798f44cb0SIgor Mitsyanko
143898f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_NO_HT40MINUS)
143998f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_NO_HT40MINUS;
144098f44cb0SIgor Mitsyanko
144198f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_NO_OFDM)
144298f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_NO_OFDM;
144398f44cb0SIgor Mitsyanko
144498f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_NO_80MHZ)
144598f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_NO_80MHZ;
144698f44cb0SIgor Mitsyanko
144798f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_NO_160MHZ)
144898f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_NO_160MHZ;
144998f44cb0SIgor Mitsyanko
145098f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_INDOOR_ONLY)
145198f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_INDOOR_ONLY;
145298f44cb0SIgor Mitsyanko
145398f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_IR_CONCURRENT)
145498f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_IR_CONCURRENT;
145598f44cb0SIgor Mitsyanko
145698f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_NO_20MHZ)
145798f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_NO_20MHZ;
145898f44cb0SIgor Mitsyanko
145998f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_NO_10MHZ)
146098f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_NO_10MHZ;
146198f44cb0SIgor Mitsyanko
146298f44cb0SIgor Mitsyanko if (qflags & QLINK_CHAN_RADAR) {
146398f44cb0SIgor Mitsyanko chan->flags |= IEEE80211_CHAN_RADAR;
146498f44cb0SIgor Mitsyanko chan->dfs_state_entered = jiffies;
146598f44cb0SIgor Mitsyanko
146698f44cb0SIgor Mitsyanko if (qchan->dfs_state == QLINK_DFS_USABLE)
146798f44cb0SIgor Mitsyanko chan->dfs_state = NL80211_DFS_USABLE;
146898f44cb0SIgor Mitsyanko else if (qchan->dfs_state ==
146998f44cb0SIgor Mitsyanko QLINK_DFS_AVAILABLE)
147098f44cb0SIgor Mitsyanko chan->dfs_state = NL80211_DFS_AVAILABLE;
147198f44cb0SIgor Mitsyanko else
147298f44cb0SIgor Mitsyanko chan->dfs_state =
147398f44cb0SIgor Mitsyanko NL80211_DFS_UNAVAILABLE;
147498f44cb0SIgor Mitsyanko }
147598f44cb0SIgor Mitsyanko
147698f44cb0SIgor Mitsyanko pr_debug("chan=%d flags=%#x max_pow=%d max_reg_pow=%d\n",
147798f44cb0SIgor Mitsyanko chan->hw_value, chan->flags, chan->max_power,
147898f44cb0SIgor Mitsyanko chan->max_reg_power);
147998f44cb0SIgor Mitsyanko break;
1480e294cbfdSIgor Mitsyanko case WLAN_EID_HT_CAPABILITY:
1481e294cbfdSIgor Mitsyanko if (unlikely(tlv_dlen !=
1482e294cbfdSIgor Mitsyanko sizeof(struct ieee80211_ht_cap))) {
1483e294cbfdSIgor Mitsyanko pr_err("bad HTCAP TLV len %zu\n", tlv_dlen);
1484e294cbfdSIgor Mitsyanko goto error_ret;
1485e294cbfdSIgor Mitsyanko }
1486e294cbfdSIgor Mitsyanko
1487e294cbfdSIgor Mitsyanko qtnf_cmd_resp_band_fill_htcap(tlv->val, &band->ht_cap);
1488e294cbfdSIgor Mitsyanko break;
1489e294cbfdSIgor Mitsyanko case WLAN_EID_VHT_CAPABILITY:
1490e294cbfdSIgor Mitsyanko if (unlikely(tlv_dlen !=
1491e294cbfdSIgor Mitsyanko sizeof(struct ieee80211_vht_cap))) {
1492e294cbfdSIgor Mitsyanko pr_err("bad VHTCAP TLV len %zu\n", tlv_dlen);
1493e294cbfdSIgor Mitsyanko goto error_ret;
1494e294cbfdSIgor Mitsyanko }
1495e294cbfdSIgor Mitsyanko
1496e294cbfdSIgor Mitsyanko qtnf_cmd_resp_band_fill_vhtcap(tlv->val,
1497e294cbfdSIgor Mitsyanko &band->vht_cap);
1498e294cbfdSIgor Mitsyanko break;
1499df0af4c7SMikhail Karpenko case QTN_TLV_ID_IFTYPE_DATA:
1500df0af4c7SMikhail Karpenko ret = qtnf_cmd_band_fill_iftype((const uint8_t *)tlv,
1501df0af4c7SMikhail Karpenko band);
1502df0af4c7SMikhail Karpenko if (ret)
1503df0af4c7SMikhail Karpenko goto error_ret;
1504df0af4c7SMikhail Karpenko break;
150598f44cb0SIgor Mitsyanko default:
150698f44cb0SIgor Mitsyanko pr_warn("unknown TLV type: %#x\n", tlv_type);
150798f44cb0SIgor Mitsyanko break;
150898f44cb0SIgor Mitsyanko }
150998f44cb0SIgor Mitsyanko }
151098f44cb0SIgor Mitsyanko
15118b0b5f1bSIgor Mitsyanko if (!qlink_tlv_parsing_ok(tlv, resp->info, payload_len)) {
15128b0b5f1bSIgor Mitsyanko pr_err("Malformed TLV buffer\n");
151398f44cb0SIgor Mitsyanko goto error_ret;
151498f44cb0SIgor Mitsyanko }
151598f44cb0SIgor Mitsyanko
151698f44cb0SIgor Mitsyanko if (band->n_channels != chidx) {
151798f44cb0SIgor Mitsyanko pr_err("channel count mismatch: reported=%d, parsed=%d\n",
151898f44cb0SIgor Mitsyanko band->n_channels, chidx);
151998f44cb0SIgor Mitsyanko goto error_ret;
152098f44cb0SIgor Mitsyanko }
152198f44cb0SIgor Mitsyanko
152298f44cb0SIgor Mitsyanko return 0;
152398f44cb0SIgor Mitsyanko
152498f44cb0SIgor Mitsyanko error_ret:
152598f44cb0SIgor Mitsyanko kfree(band->channels);
152698f44cb0SIgor Mitsyanko band->channels = NULL;
152798f44cb0SIgor Mitsyanko band->n_channels = 0;
152898f44cb0SIgor Mitsyanko
1529df0af4c7SMikhail Karpenko return ret;
153098f44cb0SIgor Mitsyanko }
153198f44cb0SIgor Mitsyanko
qtnf_cmd_get_mac_info(struct qtnf_wmac * mac)153298f44cb0SIgor Mitsyanko int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)
153398f44cb0SIgor Mitsyanko {
153498f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb, *resp_skb = NULL;
153598f44cb0SIgor Mitsyanko const struct qlink_resp_get_mac_info *resp;
15361066bd19SSergey Matyukevich size_t var_data_len = 0;
153798f44cb0SIgor Mitsyanko int ret = 0;
153898f44cb0SIgor Mitsyanko
153998f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
154098f44cb0SIgor Mitsyanko QLINK_CMD_MAC_INFO,
154198f44cb0SIgor Mitsyanko sizeof(struct qlink_cmd));
1542c93fe71cSSergey Matyukevich if (!cmd_skb)
154398f44cb0SIgor Mitsyanko return -ENOMEM;
154498f44cb0SIgor Mitsyanko
154598f44cb0SIgor Mitsyanko qtnf_bus_lock(mac->bus);
1546c6ed298fSSergey Matyukevich ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,
154798f44cb0SIgor Mitsyanko sizeof(*resp), &var_data_len);
1548c6ed298fSSergey Matyukevich if (ret)
154998f44cb0SIgor Mitsyanko goto out;
155098f44cb0SIgor Mitsyanko
155198f44cb0SIgor Mitsyanko resp = (const struct qlink_resp_get_mac_info *)resp_skb->data;
1552bc5db734SIgor Mitsyanko ret = qtnf_cmd_resp_proc_mac_info(mac, resp);
1553bc5db734SIgor Mitsyanko if (ret)
1554bc5db734SIgor Mitsyanko goto out;
1555bc5db734SIgor Mitsyanko
1556c698bce0SIgor Mitsyanko ret = qtnf_parse_variable_mac_info(mac, resp, var_data_len);
155798f44cb0SIgor Mitsyanko
155898f44cb0SIgor Mitsyanko out:
155998f44cb0SIgor Mitsyanko qtnf_bus_unlock(mac->bus);
156098f44cb0SIgor Mitsyanko consume_skb(resp_skb);
156198f44cb0SIgor Mitsyanko
156298f44cb0SIgor Mitsyanko return ret;
156398f44cb0SIgor Mitsyanko }
156498f44cb0SIgor Mitsyanko
qtnf_cmd_get_hw_info(struct qtnf_bus * bus)156598f44cb0SIgor Mitsyanko int qtnf_cmd_get_hw_info(struct qtnf_bus *bus)
156698f44cb0SIgor Mitsyanko {
156798f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb, *resp_skb = NULL;
156898f44cb0SIgor Mitsyanko const struct qlink_resp_get_hw_info *resp;
15691066bd19SSergey Matyukevich size_t info_len = 0;
157098f44cb0SIgor Mitsyanko int ret = 0;
157198f44cb0SIgor Mitsyanko
157298f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
157398f44cb0SIgor Mitsyanko QLINK_CMD_GET_HW_INFO,
157498f44cb0SIgor Mitsyanko sizeof(struct qlink_cmd));
1575c93fe71cSSergey Matyukevich if (!cmd_skb)
157698f44cb0SIgor Mitsyanko return -ENOMEM;
157798f44cb0SIgor Mitsyanko
157898f44cb0SIgor Mitsyanko qtnf_bus_lock(bus);
1579c6ed298fSSergey Matyukevich ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,
15804dd07d2bSSergey Matyukevich sizeof(*resp), &info_len);
1581c6ed298fSSergey Matyukevich if (ret)
158298f44cb0SIgor Mitsyanko goto out;
158398f44cb0SIgor Mitsyanko
158498f44cb0SIgor Mitsyanko resp = (const struct qlink_resp_get_hw_info *)resp_skb->data;
15854dd07d2bSSergey Matyukevich ret = qtnf_cmd_resp_proc_hw_info(bus, resp, info_len);
158698f44cb0SIgor Mitsyanko
158798f44cb0SIgor Mitsyanko out:
158898f44cb0SIgor Mitsyanko qtnf_bus_unlock(bus);
158998f44cb0SIgor Mitsyanko consume_skb(resp_skb);
159098f44cb0SIgor Mitsyanko
159198f44cb0SIgor Mitsyanko return ret;
159298f44cb0SIgor Mitsyanko }
159398f44cb0SIgor Mitsyanko
qtnf_cmd_band_info_get(struct qtnf_wmac * mac,struct ieee80211_supported_band * band)1594e294cbfdSIgor Mitsyanko int qtnf_cmd_band_info_get(struct qtnf_wmac *mac,
159598f44cb0SIgor Mitsyanko struct ieee80211_supported_band *band)
159698f44cb0SIgor Mitsyanko {
159798f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb, *resp_skb = NULL;
1598e294cbfdSIgor Mitsyanko struct qlink_cmd_band_info_get *cmd;
1599e294cbfdSIgor Mitsyanko struct qlink_resp_band_info_get *resp;
16001066bd19SSergey Matyukevich size_t info_len = 0;
160198f44cb0SIgor Mitsyanko int ret = 0;
16022c31129fSIgor Mitsyanko u8 qband = qlink_utils_band_cfg2q(band->band);
160398f44cb0SIgor Mitsyanko
1604bc0384eeSColin Ian King cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
1605e294cbfdSIgor Mitsyanko QLINK_CMD_BAND_INFO_GET,
1606bc0384eeSColin Ian King sizeof(*cmd));
1607bc0384eeSColin Ian King if (!cmd_skb)
1608bc0384eeSColin Ian King return -ENOMEM;
1609bc0384eeSColin Ian King
1610e294cbfdSIgor Mitsyanko cmd = (struct qlink_cmd_band_info_get *)cmd_skb->data;
161198f44cb0SIgor Mitsyanko cmd->band = qband;
16129ef75095SSergey Matyukevich
16139ef75095SSergey Matyukevich qtnf_bus_lock(mac->bus);
1614c6ed298fSSergey Matyukevich ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,
161598f44cb0SIgor Mitsyanko sizeof(*resp), &info_len);
1616c6ed298fSSergey Matyukevich if (ret)
161798f44cb0SIgor Mitsyanko goto out;
161898f44cb0SIgor Mitsyanko
1619e294cbfdSIgor Mitsyanko resp = (struct qlink_resp_band_info_get *)resp_skb->data;
162098f44cb0SIgor Mitsyanko if (resp->band != qband) {
162198f44cb0SIgor Mitsyanko pr_err("MAC%u: reply band %u != cmd band %u\n", mac->macid,
162298f44cb0SIgor Mitsyanko resp->band, qband);
162398f44cb0SIgor Mitsyanko ret = -EINVAL;
162498f44cb0SIgor Mitsyanko goto out;
162598f44cb0SIgor Mitsyanko }
162698f44cb0SIgor Mitsyanko
1627e294cbfdSIgor Mitsyanko ret = qtnf_cmd_resp_fill_band_info(band, resp, info_len);
162898f44cb0SIgor Mitsyanko
162998f44cb0SIgor Mitsyanko out:
16309ef75095SSergey Matyukevich qtnf_bus_unlock(mac->bus);
163198f44cb0SIgor Mitsyanko consume_skb(resp_skb);
163298f44cb0SIgor Mitsyanko
163398f44cb0SIgor Mitsyanko return ret;
163498f44cb0SIgor Mitsyanko }
163598f44cb0SIgor Mitsyanko
qtnf_cmd_send_update_phy_params(struct qtnf_wmac * mac,u32 changed)163698f44cb0SIgor Mitsyanko int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed)
163798f44cb0SIgor Mitsyanko {
163898f44cb0SIgor Mitsyanko struct wiphy *wiphy = priv_to_wiphy(mac);
163998f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
164098f44cb0SIgor Mitsyanko int ret = 0;
164198f44cb0SIgor Mitsyanko
164298f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
164398f44cb0SIgor Mitsyanko QLINK_CMD_PHY_PARAMS_SET,
164498f44cb0SIgor Mitsyanko sizeof(struct qlink_cmd));
164598f44cb0SIgor Mitsyanko if (!cmd_skb)
164698f44cb0SIgor Mitsyanko return -ENOMEM;
164798f44cb0SIgor Mitsyanko
164898f44cb0SIgor Mitsyanko qtnf_bus_lock(mac->bus);
164998f44cb0SIgor Mitsyanko
165098f44cb0SIgor Mitsyanko if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
16519fe504a1SSergey Matyukevich qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_FRAG_THRESH,
165298f44cb0SIgor Mitsyanko wiphy->frag_threshold);
165398f44cb0SIgor Mitsyanko if (changed & WIPHY_PARAM_RTS_THRESHOLD)
16549fe504a1SSergey Matyukevich qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_RTS_THRESH,
165598f44cb0SIgor Mitsyanko wiphy->rts_threshold);
165698f44cb0SIgor Mitsyanko if (changed & WIPHY_PARAM_COVERAGE_CLASS)
16578b0b5f1bSIgor Mitsyanko qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS,
165898f44cb0SIgor Mitsyanko wiphy->coverage_class);
165998f44cb0SIgor Mitsyanko
1660f3c8bd46SSergey Matyukevich if (changed & WIPHY_PARAM_RETRY_LONG)
16618b0b5f1bSIgor Mitsyanko qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_LRETRY_LIMIT,
1662f3c8bd46SSergey Matyukevich wiphy->retry_long);
1663f3c8bd46SSergey Matyukevich
1664f3c8bd46SSergey Matyukevich if (changed & WIPHY_PARAM_RETRY_SHORT)
16658b0b5f1bSIgor Mitsyanko qtnf_cmd_skb_put_tlv_u32(cmd_skb, QTN_TLV_ID_SRETRY_LIMIT,
1666f3c8bd46SSergey Matyukevich wiphy->retry_short);
1667f3c8bd46SSergey Matyukevich
1668c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(mac->bus, cmd_skb);
166998f44cb0SIgor Mitsyanko
167098f44cb0SIgor Mitsyanko qtnf_bus_unlock(mac->bus);
1671c6ed298fSSergey Matyukevich
167298f44cb0SIgor Mitsyanko return ret;
167398f44cb0SIgor Mitsyanko }
167498f44cb0SIgor Mitsyanko
qtnf_cmd_send_init_fw(struct qtnf_bus * bus)167598f44cb0SIgor Mitsyanko int qtnf_cmd_send_init_fw(struct qtnf_bus *bus)
167698f44cb0SIgor Mitsyanko {
1677a3ebb033SIgor Mitsyanko struct sk_buff *resp_skb = NULL;
1678a3ebb033SIgor Mitsyanko struct qlink_resp_init_fw *resp;
1679a3ebb033SIgor Mitsyanko struct qlink_cmd_init_fw *cmd;
168098f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
1681a3ebb033SIgor Mitsyanko size_t info_len = 0;
1682a3ebb033SIgor Mitsyanko int ret;
168398f44cb0SIgor Mitsyanko
168498f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
168598f44cb0SIgor Mitsyanko QLINK_CMD_FW_INIT,
1686a3ebb033SIgor Mitsyanko sizeof(*cmd));
1687c93fe71cSSergey Matyukevich if (!cmd_skb)
168898f44cb0SIgor Mitsyanko return -ENOMEM;
168998f44cb0SIgor Mitsyanko
1690a3ebb033SIgor Mitsyanko cmd = (struct qlink_cmd_init_fw *)cmd_skb->data;
1691a3ebb033SIgor Mitsyanko cmd->qlink_proto_ver = cpu_to_le32(QLINK_PROTO_VER);
1692a3ebb033SIgor Mitsyanko
169398f44cb0SIgor Mitsyanko qtnf_bus_lock(bus);
1694a3ebb033SIgor Mitsyanko ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,
1695a3ebb033SIgor Mitsyanko sizeof(*resp), &info_len);
1696a3ebb033SIgor Mitsyanko qtnf_bus_unlock(bus);
1697a3ebb033SIgor Mitsyanko
1698c6ed298fSSergey Matyukevich if (ret)
169998f44cb0SIgor Mitsyanko goto out;
170098f44cb0SIgor Mitsyanko
1701a3ebb033SIgor Mitsyanko resp = (struct qlink_resp_init_fw *)resp_skb->data;
1702a3ebb033SIgor Mitsyanko bus->hw_info.ql_proto_ver = le32_to_cpu(resp->qlink_proto_ver);
1703c6ed298fSSergey Matyukevich
1704a3ebb033SIgor Mitsyanko out:
1705a3ebb033SIgor Mitsyanko consume_skb(resp_skb);
170698f44cb0SIgor Mitsyanko return ret;
170798f44cb0SIgor Mitsyanko }
170898f44cb0SIgor Mitsyanko
qtnf_cmd_send_deinit_fw(struct qtnf_bus * bus)170998f44cb0SIgor Mitsyanko void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus)
171098f44cb0SIgor Mitsyanko {
171198f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
171298f44cb0SIgor Mitsyanko
171398f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
171498f44cb0SIgor Mitsyanko QLINK_CMD_FW_DEINIT,
171598f44cb0SIgor Mitsyanko sizeof(struct qlink_cmd));
171698f44cb0SIgor Mitsyanko if (!cmd_skb)
171798f44cb0SIgor Mitsyanko return;
171898f44cb0SIgor Mitsyanko
171998f44cb0SIgor Mitsyanko qtnf_bus_lock(bus);
1720c6ed298fSSergey Matyukevich qtnf_cmd_send(bus, cmd_skb);
172198f44cb0SIgor Mitsyanko qtnf_bus_unlock(bus);
172298f44cb0SIgor Mitsyanko }
172398f44cb0SIgor Mitsyanko
qtnf_cmd_send_add_key(struct qtnf_vif * vif,u8 key_index,bool pairwise,const u8 * mac_addr,struct key_params * params)172498f44cb0SIgor Mitsyanko int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
172598f44cb0SIgor Mitsyanko const u8 *mac_addr, struct key_params *params)
172698f44cb0SIgor Mitsyanko {
172798f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
172898f44cb0SIgor Mitsyanko struct qlink_cmd_add_key *cmd;
172998f44cb0SIgor Mitsyanko int ret = 0;
173098f44cb0SIgor Mitsyanko
173198f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
173298f44cb0SIgor Mitsyanko QLINK_CMD_ADD_KEY,
173398f44cb0SIgor Mitsyanko sizeof(*cmd));
1734c93fe71cSSergey Matyukevich if (!cmd_skb)
173598f44cb0SIgor Mitsyanko return -ENOMEM;
173698f44cb0SIgor Mitsyanko
173798f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
173898f44cb0SIgor Mitsyanko
173998f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_add_key *)cmd_skb->data;
174098f44cb0SIgor Mitsyanko
174198f44cb0SIgor Mitsyanko if (mac_addr)
174298f44cb0SIgor Mitsyanko ether_addr_copy(cmd->addr, mac_addr);
174398f44cb0SIgor Mitsyanko else
174498f44cb0SIgor Mitsyanko eth_broadcast_addr(cmd->addr);
174598f44cb0SIgor Mitsyanko
174698f44cb0SIgor Mitsyanko cmd->cipher = cpu_to_le32(params->cipher);
174798f44cb0SIgor Mitsyanko cmd->key_index = key_index;
174898f44cb0SIgor Mitsyanko cmd->pairwise = pairwise;
174998f44cb0SIgor Mitsyanko
175098f44cb0SIgor Mitsyanko if (params->key && params->key_len > 0)
175198f44cb0SIgor Mitsyanko qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_KEY,
175298f44cb0SIgor Mitsyanko params->key,
175398f44cb0SIgor Mitsyanko params->key_len);
175498f44cb0SIgor Mitsyanko
175598f44cb0SIgor Mitsyanko if (params->seq && params->seq_len > 0)
175698f44cb0SIgor Mitsyanko qtnf_cmd_skb_put_tlv_arr(cmd_skb, QTN_TLV_ID_SEQ,
175798f44cb0SIgor Mitsyanko params->seq,
175898f44cb0SIgor Mitsyanko params->seq_len);
175998f44cb0SIgor Mitsyanko
1760c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
176198f44cb0SIgor Mitsyanko
176298f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
1763c6ed298fSSergey Matyukevich
176498f44cb0SIgor Mitsyanko return ret;
176598f44cb0SIgor Mitsyanko }
176698f44cb0SIgor Mitsyanko
qtnf_cmd_send_del_key(struct qtnf_vif * vif,u8 key_index,bool pairwise,const u8 * mac_addr)176798f44cb0SIgor Mitsyanko int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
176898f44cb0SIgor Mitsyanko const u8 *mac_addr)
176998f44cb0SIgor Mitsyanko {
177098f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
177198f44cb0SIgor Mitsyanko struct qlink_cmd_del_key *cmd;
177298f44cb0SIgor Mitsyanko int ret = 0;
177398f44cb0SIgor Mitsyanko
177498f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
177598f44cb0SIgor Mitsyanko QLINK_CMD_DEL_KEY,
177698f44cb0SIgor Mitsyanko sizeof(*cmd));
1777c93fe71cSSergey Matyukevich if (!cmd_skb)
177898f44cb0SIgor Mitsyanko return -ENOMEM;
177998f44cb0SIgor Mitsyanko
178098f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
178198f44cb0SIgor Mitsyanko
178298f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_del_key *)cmd_skb->data;
178398f44cb0SIgor Mitsyanko
178498f44cb0SIgor Mitsyanko if (mac_addr)
178598f44cb0SIgor Mitsyanko ether_addr_copy(cmd->addr, mac_addr);
178698f44cb0SIgor Mitsyanko else
178798f44cb0SIgor Mitsyanko eth_broadcast_addr(cmd->addr);
178898f44cb0SIgor Mitsyanko
178998f44cb0SIgor Mitsyanko cmd->key_index = key_index;
179098f44cb0SIgor Mitsyanko cmd->pairwise = pairwise;
179198f44cb0SIgor Mitsyanko
1792c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
179398f44cb0SIgor Mitsyanko
179498f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
1795c6ed298fSSergey Matyukevich
179698f44cb0SIgor Mitsyanko return ret;
179798f44cb0SIgor Mitsyanko }
179898f44cb0SIgor Mitsyanko
qtnf_cmd_send_set_default_key(struct qtnf_vif * vif,u8 key_index,bool unicast,bool multicast)179998f44cb0SIgor Mitsyanko int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,
180098f44cb0SIgor Mitsyanko bool unicast, bool multicast)
180198f44cb0SIgor Mitsyanko {
180298f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
180398f44cb0SIgor Mitsyanko struct qlink_cmd_set_def_key *cmd;
180498f44cb0SIgor Mitsyanko int ret = 0;
180598f44cb0SIgor Mitsyanko
180698f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
180798f44cb0SIgor Mitsyanko QLINK_CMD_SET_DEFAULT_KEY,
180898f44cb0SIgor Mitsyanko sizeof(*cmd));
1809c93fe71cSSergey Matyukevich if (!cmd_skb)
181098f44cb0SIgor Mitsyanko return -ENOMEM;
181198f44cb0SIgor Mitsyanko
181298f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
181398f44cb0SIgor Mitsyanko
181498f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_set_def_key *)cmd_skb->data;
181598f44cb0SIgor Mitsyanko cmd->key_index = key_index;
181698f44cb0SIgor Mitsyanko cmd->unicast = unicast;
181798f44cb0SIgor Mitsyanko cmd->multicast = multicast;
181898f44cb0SIgor Mitsyanko
1819c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
182098f44cb0SIgor Mitsyanko
182198f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
1822c6ed298fSSergey Matyukevich
182398f44cb0SIgor Mitsyanko return ret;
182498f44cb0SIgor Mitsyanko }
182598f44cb0SIgor Mitsyanko
qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif * vif,u8 key_index)182698f44cb0SIgor Mitsyanko int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index)
182798f44cb0SIgor Mitsyanko {
182898f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
182998f44cb0SIgor Mitsyanko struct qlink_cmd_set_def_mgmt_key *cmd;
183098f44cb0SIgor Mitsyanko int ret = 0;
183198f44cb0SIgor Mitsyanko
183298f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
183398f44cb0SIgor Mitsyanko QLINK_CMD_SET_DEFAULT_MGMT_KEY,
183498f44cb0SIgor Mitsyanko sizeof(*cmd));
1835c93fe71cSSergey Matyukevich if (!cmd_skb)
183698f44cb0SIgor Mitsyanko return -ENOMEM;
183798f44cb0SIgor Mitsyanko
183898f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
183998f44cb0SIgor Mitsyanko
184098f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data;
184198f44cb0SIgor Mitsyanko cmd->key_index = key_index;
184298f44cb0SIgor Mitsyanko
1843c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
184498f44cb0SIgor Mitsyanko
184598f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
1846c6ed298fSSergey Matyukevich
184798f44cb0SIgor Mitsyanko return ret;
184898f44cb0SIgor Mitsyanko }
184998f44cb0SIgor Mitsyanko
qtnf_encode_sta_flags(u32 flags)185098f44cb0SIgor Mitsyanko static u32 qtnf_encode_sta_flags(u32 flags)
185198f44cb0SIgor Mitsyanko {
185298f44cb0SIgor Mitsyanko u32 code = 0;
185398f44cb0SIgor Mitsyanko
185498f44cb0SIgor Mitsyanko if (flags & BIT(NL80211_STA_FLAG_AUTHORIZED))
185598f44cb0SIgor Mitsyanko code |= QLINK_STA_FLAG_AUTHORIZED;
185698f44cb0SIgor Mitsyanko if (flags & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
185798f44cb0SIgor Mitsyanko code |= QLINK_STA_FLAG_SHORT_PREAMBLE;
185898f44cb0SIgor Mitsyanko if (flags & BIT(NL80211_STA_FLAG_WME))
185998f44cb0SIgor Mitsyanko code |= QLINK_STA_FLAG_WME;
186098f44cb0SIgor Mitsyanko if (flags & BIT(NL80211_STA_FLAG_MFP))
186198f44cb0SIgor Mitsyanko code |= QLINK_STA_FLAG_MFP;
186298f44cb0SIgor Mitsyanko if (flags & BIT(NL80211_STA_FLAG_AUTHENTICATED))
186398f44cb0SIgor Mitsyanko code |= QLINK_STA_FLAG_AUTHENTICATED;
186498f44cb0SIgor Mitsyanko if (flags & BIT(NL80211_STA_FLAG_TDLS_PEER))
186598f44cb0SIgor Mitsyanko code |= QLINK_STA_FLAG_TDLS_PEER;
186698f44cb0SIgor Mitsyanko if (flags & BIT(NL80211_STA_FLAG_ASSOCIATED))
186798f44cb0SIgor Mitsyanko code |= QLINK_STA_FLAG_ASSOCIATED;
186898f44cb0SIgor Mitsyanko return code;
186998f44cb0SIgor Mitsyanko }
187098f44cb0SIgor Mitsyanko
qtnf_cmd_send_change_sta(struct qtnf_vif * vif,const u8 * mac,struct station_parameters * params)187198f44cb0SIgor Mitsyanko int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,
187298f44cb0SIgor Mitsyanko struct station_parameters *params)
187398f44cb0SIgor Mitsyanko {
187498f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
187598f44cb0SIgor Mitsyanko struct qlink_cmd_change_sta *cmd;
187698f44cb0SIgor Mitsyanko int ret = 0;
187798f44cb0SIgor Mitsyanko
187898f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
187998f44cb0SIgor Mitsyanko QLINK_CMD_CHANGE_STA,
188098f44cb0SIgor Mitsyanko sizeof(*cmd));
1881c93fe71cSSergey Matyukevich if (!cmd_skb)
188298f44cb0SIgor Mitsyanko return -ENOMEM;
188398f44cb0SIgor Mitsyanko
188498f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
188598f44cb0SIgor Mitsyanko
188698f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_change_sta *)cmd_skb->data;
188798f44cb0SIgor Mitsyanko ether_addr_copy(cmd->sta_addr, mac);
18884d2a7a1cSIgor Mitsyanko cmd->flag_update.mask =
18894d2a7a1cSIgor Mitsyanko cpu_to_le32(qtnf_encode_sta_flags(params->sta_flags_mask));
18904d2a7a1cSIgor Mitsyanko cmd->flag_update.value =
18914d2a7a1cSIgor Mitsyanko cpu_to_le32(qtnf_encode_sta_flags(params->sta_flags_set));
1892805b28c0SSergey Matyukevich
1893805b28c0SSergey Matyukevich switch (vif->wdev.iftype) {
1894805b28c0SSergey Matyukevich case NL80211_IFTYPE_AP:
1895805b28c0SSergey Matyukevich cmd->if_type = cpu_to_le16(QLINK_IFTYPE_AP);
1896805b28c0SSergey Matyukevich break;
1897805b28c0SSergey Matyukevich case NL80211_IFTYPE_STATION:
1898805b28c0SSergey Matyukevich cmd->if_type = cpu_to_le16(QLINK_IFTYPE_STATION);
1899805b28c0SSergey Matyukevich break;
1900805b28c0SSergey Matyukevich default:
1901805b28c0SSergey Matyukevich pr_err("unsupported iftype %d\n", vif->wdev.iftype);
190263f69820SColin Ian King dev_kfree_skb(cmd_skb);
1903805b28c0SSergey Matyukevich ret = -EINVAL;
1904805b28c0SSergey Matyukevich goto out;
1905805b28c0SSergey Matyukevich }
190698f44cb0SIgor Mitsyanko
1907c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
190898f44cb0SIgor Mitsyanko
190998f44cb0SIgor Mitsyanko out:
191098f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
1911c6ed298fSSergey Matyukevich
191298f44cb0SIgor Mitsyanko return ret;
191398f44cb0SIgor Mitsyanko }
191498f44cb0SIgor Mitsyanko
qtnf_cmd_send_del_sta(struct qtnf_vif * vif,struct station_del_parameters * params)191598f44cb0SIgor Mitsyanko int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,
191698f44cb0SIgor Mitsyanko struct station_del_parameters *params)
191798f44cb0SIgor Mitsyanko {
191898f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
191998f44cb0SIgor Mitsyanko struct qlink_cmd_del_sta *cmd;
192098f44cb0SIgor Mitsyanko int ret = 0;
192198f44cb0SIgor Mitsyanko
192298f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
192398f44cb0SIgor Mitsyanko QLINK_CMD_DEL_STA,
192498f44cb0SIgor Mitsyanko sizeof(*cmd));
1925c93fe71cSSergey Matyukevich if (!cmd_skb)
192698f44cb0SIgor Mitsyanko return -ENOMEM;
192798f44cb0SIgor Mitsyanko
192898f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
192998f44cb0SIgor Mitsyanko
193098f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_del_sta *)cmd_skb->data;
193198f44cb0SIgor Mitsyanko
193298f44cb0SIgor Mitsyanko if (params->mac)
193398f44cb0SIgor Mitsyanko ether_addr_copy(cmd->sta_addr, params->mac);
193498f44cb0SIgor Mitsyanko else
193598f44cb0SIgor Mitsyanko eth_broadcast_addr(cmd->sta_addr); /* flush all stations */
193698f44cb0SIgor Mitsyanko
193798f44cb0SIgor Mitsyanko cmd->subtype = params->subtype;
193898f44cb0SIgor Mitsyanko cmd->reason_code = cpu_to_le16(params->reason_code);
193998f44cb0SIgor Mitsyanko
1940c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
194198f44cb0SIgor Mitsyanko
194298f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
1943c6ed298fSSergey Matyukevich
194498f44cb0SIgor Mitsyanko return ret;
194598f44cb0SIgor Mitsyanko }
194698f44cb0SIgor Mitsyanko
qtnf_cmd_channel_tlv_add(struct sk_buff * cmd_skb,const struct ieee80211_channel * sc)1947c9889671SIgor Mitsyanko static void qtnf_cmd_channel_tlv_add(struct sk_buff *cmd_skb,
1948c9889671SIgor Mitsyanko const struct ieee80211_channel *sc)
1949c9889671SIgor Mitsyanko {
19502c31129fSIgor Mitsyanko struct qlink_tlv_channel *tlv;
19512c31129fSIgor Mitsyanko struct qlink_channel *qch;
1952c9889671SIgor Mitsyanko
19532c31129fSIgor Mitsyanko tlv = skb_put_zero(cmd_skb, sizeof(*tlv));
19542c31129fSIgor Mitsyanko qch = &tlv->chan;
19552c31129fSIgor Mitsyanko tlv->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL);
19562c31129fSIgor Mitsyanko tlv->hdr.len = cpu_to_le16(sizeof(*qch));
1957c9889671SIgor Mitsyanko
19582c31129fSIgor Mitsyanko qch->center_freq = cpu_to_le16(sc->center_freq);
19592c31129fSIgor Mitsyanko qch->hw_value = cpu_to_le16(sc->hw_value);
19602c31129fSIgor Mitsyanko qch->band = qlink_utils_band_cfg2q(sc->band);
19612c31129fSIgor Mitsyanko qch->max_power = sc->max_power;
19622c31129fSIgor Mitsyanko qch->max_reg_power = sc->max_reg_power;
19632c31129fSIgor Mitsyanko qch->max_antenna_gain = sc->max_antenna_gain;
19642c31129fSIgor Mitsyanko qch->beacon_found = sc->beacon_found;
19652c31129fSIgor Mitsyanko qch->dfs_state = qlink_utils_dfs_state_cfg2q(sc->dfs_state);
19662c31129fSIgor Mitsyanko qch->flags = cpu_to_le32(qlink_utils_chflags_cfg2q(sc->flags));
1967c9889671SIgor Mitsyanko }
1968c9889671SIgor Mitsyanko
qtnf_cmd_randmac_tlv_add(struct sk_buff * cmd_skb,const u8 * mac_addr,const u8 * mac_addr_mask)19696fbef954SAndrey Shevchenko static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb,
19706fbef954SAndrey Shevchenko const u8 *mac_addr,
19716fbef954SAndrey Shevchenko const u8 *mac_addr_mask)
19726fbef954SAndrey Shevchenko {
19736fbef954SAndrey Shevchenko struct qlink_random_mac_addr *randmac;
19746fbef954SAndrey Shevchenko struct qlink_tlv_hdr *hdr =
19756fbef954SAndrey Shevchenko skb_put(cmd_skb, sizeof(*hdr) + sizeof(*randmac));
19766fbef954SAndrey Shevchenko
19776fbef954SAndrey Shevchenko hdr->type = cpu_to_le16(QTN_TLV_ID_RANDOM_MAC_ADDR);
19786fbef954SAndrey Shevchenko hdr->len = cpu_to_le16(sizeof(*randmac));
19796fbef954SAndrey Shevchenko randmac = (struct qlink_random_mac_addr *)hdr->val;
19806fbef954SAndrey Shevchenko
19816fbef954SAndrey Shevchenko memcpy(randmac->mac_addr, mac_addr, ETH_ALEN);
19826fbef954SAndrey Shevchenko memcpy(randmac->mac_addr_mask, mac_addr_mask, ETH_ALEN);
19836fbef954SAndrey Shevchenko }
19846fbef954SAndrey Shevchenko
qtnf_cmd_send_scan(struct qtnf_wmac * mac)198598f44cb0SIgor Mitsyanko int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
198698f44cb0SIgor Mitsyanko {
198798f44cb0SIgor Mitsyanko struct cfg80211_scan_request *scan_req = mac->scan_req;
1988501c3be1SIgor Mitsyanko u16 dwell_passive = QTNF_SCAN_DWELL_PASSIVE_DEFAULT;
1989501c3be1SIgor Mitsyanko u16 dwell_active = QTNF_SCAN_DWELL_ACTIVE_DEFAULT;
1990501c3be1SIgor Mitsyanko struct wireless_dev *wdev = scan_req->wdev;
1991501c3be1SIgor Mitsyanko struct ieee80211_channel *sc;
1992501c3be1SIgor Mitsyanko struct qlink_cmd_scan *cmd;
1993501c3be1SIgor Mitsyanko struct sk_buff *cmd_skb;
1994501c3be1SIgor Mitsyanko int n_channels = 0;
1995501c3be1SIgor Mitsyanko u64 flags = 0;
1996501c3be1SIgor Mitsyanko int count;
199798f44cb0SIgor Mitsyanko int ret;
199898f44cb0SIgor Mitsyanko
199998f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
200098f44cb0SIgor Mitsyanko QLINK_CMD_SCAN,
2001501c3be1SIgor Mitsyanko sizeof(*cmd));
2002c93fe71cSSergey Matyukevich if (!cmd_skb)
200398f44cb0SIgor Mitsyanko return -ENOMEM;
200498f44cb0SIgor Mitsyanko
2005501c3be1SIgor Mitsyanko cmd = (struct qlink_cmd_scan *)cmd_skb->data;
200698f44cb0SIgor Mitsyanko
2007501c3be1SIgor Mitsyanko if (scan_req->duration) {
2008501c3be1SIgor Mitsyanko dwell_active = scan_req->duration;
2009501c3be1SIgor Mitsyanko dwell_passive = scan_req->duration;
2010501c3be1SIgor Mitsyanko } else if (wdev->iftype == NL80211_IFTYPE_STATION &&
20117b0a0e3cSJohannes Berg wdev->connected) {
2012501c3be1SIgor Mitsyanko /* let device select dwell based on traffic conditions */
2013501c3be1SIgor Mitsyanko dwell_active = QTNF_SCAN_TIME_AUTO;
2014501c3be1SIgor Mitsyanko dwell_passive = QTNF_SCAN_TIME_AUTO;
2015501c3be1SIgor Mitsyanko }
2016501c3be1SIgor Mitsyanko
2017501c3be1SIgor Mitsyanko cmd->n_ssids = cpu_to_le16(scan_req->n_ssids);
2018501c3be1SIgor Mitsyanko for (count = 0; count < scan_req->n_ssids; ++count) {
201998f44cb0SIgor Mitsyanko qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID,
202098f44cb0SIgor Mitsyanko scan_req->ssids[count].ssid,
202198f44cb0SIgor Mitsyanko scan_req->ssids[count].ssid_len);
202298f44cb0SIgor Mitsyanko }
202398f44cb0SIgor Mitsyanko
202498f44cb0SIgor Mitsyanko if (scan_req->ie_len != 0)
202518b7470fSIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_PROBE_REQ,
202618b7470fSIgor Mitsyanko scan_req->ie, scan_req->ie_len);
202798f44cb0SIgor Mitsyanko
2028501c3be1SIgor Mitsyanko for (count = 0; count < scan_req->n_channels; ++count) {
202998f44cb0SIgor Mitsyanko sc = scan_req->channels[count];
2030501c3be1SIgor Mitsyanko if (sc->flags & IEEE80211_CHAN_DISABLED)
203198f44cb0SIgor Mitsyanko continue;
203298f44cb0SIgor Mitsyanko
2033501c3be1SIgor Mitsyanko pr_debug("[MAC%u] scan chan=%d, freq=%d, flags=%#x\n",
203498f44cb0SIgor Mitsyanko mac->macid, sc->hw_value, sc->center_freq,
203598f44cb0SIgor Mitsyanko sc->flags);
203698f44cb0SIgor Mitsyanko
2037c9889671SIgor Mitsyanko qtnf_cmd_channel_tlv_add(cmd_skb, sc);
2038501c3be1SIgor Mitsyanko ++n_channels;
203998f44cb0SIgor Mitsyanko }
204098f44cb0SIgor Mitsyanko
2041501c3be1SIgor Mitsyanko if (scan_req->flags & NL80211_SCAN_FLAG_FLUSH)
2042501c3be1SIgor Mitsyanko flags |= QLINK_SCAN_FLAG_FLUSH;
2043501c3be1SIgor Mitsyanko
2044501c3be1SIgor Mitsyanko if (scan_req->duration_mandatory)
2045501c3be1SIgor Mitsyanko flags |= QLINK_SCAN_FLAG_DURATION_MANDATORY;
2046501c3be1SIgor Mitsyanko
2047501c3be1SIgor Mitsyanko cmd->n_channels = cpu_to_le16(n_channels);
2048501c3be1SIgor Mitsyanko cmd->active_dwell = cpu_to_le16(dwell_active);
2049501c3be1SIgor Mitsyanko cmd->passive_dwell = cpu_to_le16(dwell_passive);
2050501c3be1SIgor Mitsyanko cmd->sample_duration = cpu_to_le16(QTNF_SCAN_SAMPLE_DURATION_DEFAULT);
2051501c3be1SIgor Mitsyanko cmd->flags = cpu_to_le64(flags);
2052501c3be1SIgor Mitsyanko
2053501c3be1SIgor Mitsyanko pr_debug("[MAC%u] %s scan dwell active=%u passive=%u duration=%u\n",
2054501c3be1SIgor Mitsyanko mac->macid,
2055501c3be1SIgor Mitsyanko scan_req->duration_mandatory ? "mandatory" : "max",
2056501c3be1SIgor Mitsyanko dwell_active, dwell_passive,
2057501c3be1SIgor Mitsyanko QTNF_SCAN_SAMPLE_DURATION_DEFAULT);
2058b63967caSIgor Mitsyanko
20596fbef954SAndrey Shevchenko if (scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
2060501c3be1SIgor Mitsyanko pr_debug("[MAC%u] scan with random addr=%pM, mask=%pM\n",
20616fbef954SAndrey Shevchenko mac->macid,
20626fbef954SAndrey Shevchenko scan_req->mac_addr, scan_req->mac_addr_mask);
20636fbef954SAndrey Shevchenko qtnf_cmd_randmac_tlv_add(cmd_skb, scan_req->mac_addr,
20646fbef954SAndrey Shevchenko scan_req->mac_addr_mask);
20656fbef954SAndrey Shevchenko }
20666fbef954SAndrey Shevchenko
2067501c3be1SIgor Mitsyanko qtnf_bus_lock(mac->bus);
2068c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(mac->bus, cmd_skb);
206998f44cb0SIgor Mitsyanko qtnf_bus_unlock(mac->bus);
2070c6ed298fSSergey Matyukevich
207198f44cb0SIgor Mitsyanko return ret;
207298f44cb0SIgor Mitsyanko }
207398f44cb0SIgor Mitsyanko
qtnf_cmd_send_connect(struct qtnf_vif * vif,struct cfg80211_connect_params * sme)207498f44cb0SIgor Mitsyanko int qtnf_cmd_send_connect(struct qtnf_vif *vif,
207598f44cb0SIgor Mitsyanko struct cfg80211_connect_params *sme)
207698f44cb0SIgor Mitsyanko {
207798f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
207898f44cb0SIgor Mitsyanko struct qlink_cmd_connect *cmd;
2079d23d1361SIgor Mitsyanko struct qlink_auth_encr *aen;
208098f44cb0SIgor Mitsyanko int ret;
208198f44cb0SIgor Mitsyanko int i;
2082ecad3b0bSVeerendranath Jakkam int n;
20839766d1ddSIgor Mitsyanko u32 connect_flags = 0;
208498f44cb0SIgor Mitsyanko
208598f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
208698f44cb0SIgor Mitsyanko QLINK_CMD_CONNECT,
208798f44cb0SIgor Mitsyanko sizeof(*cmd));
2088c93fe71cSSergey Matyukevich if (!cmd_skb)
208998f44cb0SIgor Mitsyanko return -ENOMEM;
209098f44cb0SIgor Mitsyanko
209198f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_connect *)cmd_skb->data;
209298f44cb0SIgor Mitsyanko
20939766d1ddSIgor Mitsyanko ether_addr_copy(cmd->bssid, vif->bssid);
209498f44cb0SIgor Mitsyanko
2095c9889671SIgor Mitsyanko if (sme->bssid_hint)
2096c9889671SIgor Mitsyanko ether_addr_copy(cmd->bssid_hint, sme->bssid_hint);
209796d4eaf2SIgor Mitsyanko else
2098c9889671SIgor Mitsyanko eth_zero_addr(cmd->bssid_hint);
2099c9889671SIgor Mitsyanko
2100c9889671SIgor Mitsyanko if (sme->prev_bssid)
2101c9889671SIgor Mitsyanko ether_addr_copy(cmd->prev_bssid, sme->prev_bssid);
2102c9889671SIgor Mitsyanko else
2103c9889671SIgor Mitsyanko eth_zero_addr(cmd->prev_bssid);
210498f44cb0SIgor Mitsyanko
2105f5d2ff43SAndrey Shevchenko if ((sme->bg_scan_period >= 0) &&
2106f5d2ff43SAndrey Shevchenko (sme->bg_scan_period <= SHRT_MAX))
21079766d1ddSIgor Mitsyanko cmd->bg_scan_period = cpu_to_le16(sme->bg_scan_period);
21089766d1ddSIgor Mitsyanko else
2109f5d2ff43SAndrey Shevchenko cmd->bg_scan_period = cpu_to_le16(-1); /* use default value */
21109766d1ddSIgor Mitsyanko
21119766d1ddSIgor Mitsyanko if (sme->flags & ASSOC_REQ_DISABLE_HT)
21129766d1ddSIgor Mitsyanko connect_flags |= QLINK_STA_CONNECT_DISABLE_HT;
21139766d1ddSIgor Mitsyanko if (sme->flags & ASSOC_REQ_DISABLE_VHT)
21149766d1ddSIgor Mitsyanko connect_flags |= QLINK_STA_CONNECT_DISABLE_VHT;
21159766d1ddSIgor Mitsyanko if (sme->flags & ASSOC_REQ_USE_RRM)
21169766d1ddSIgor Mitsyanko connect_flags |= QLINK_STA_CONNECT_USE_RRM;
21179766d1ddSIgor Mitsyanko
21189766d1ddSIgor Mitsyanko cmd->flags = cpu_to_le32(connect_flags);
2119c9889671SIgor Mitsyanko memcpy(&cmd->ht_capa, &sme->ht_capa, sizeof(cmd->ht_capa));
2120c9889671SIgor Mitsyanko memcpy(&cmd->ht_capa_mask, &sme->ht_capa_mask,
2121c9889671SIgor Mitsyanko sizeof(cmd->ht_capa_mask));
2122c9889671SIgor Mitsyanko memcpy(&cmd->vht_capa, &sme->vht_capa, sizeof(cmd->vht_capa));
2123c9889671SIgor Mitsyanko memcpy(&cmd->vht_capa_mask, &sme->vht_capa_mask,
2124c9889671SIgor Mitsyanko sizeof(cmd->vht_capa_mask));
2125c9889671SIgor Mitsyanko cmd->pbss = sme->pbss;
212698f44cb0SIgor Mitsyanko
2127d23d1361SIgor Mitsyanko aen = &cmd->aen;
2128d23d1361SIgor Mitsyanko aen->auth_type = sme->auth_type;
2129d23d1361SIgor Mitsyanko aen->privacy = !!sme->privacy;
2130c9889671SIgor Mitsyanko cmd->mfp = sme->mfp;
2131d23d1361SIgor Mitsyanko aen->wpa_versions = cpu_to_le32(sme->crypto.wpa_versions);
2132d23d1361SIgor Mitsyanko aen->cipher_group = cpu_to_le32(sme->crypto.cipher_group);
2133d23d1361SIgor Mitsyanko aen->n_ciphers_pairwise = cpu_to_le32(sme->crypto.n_ciphers_pairwise);
213498f44cb0SIgor Mitsyanko
213598f44cb0SIgor Mitsyanko for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++)
2136d23d1361SIgor Mitsyanko aen->ciphers_pairwise[i] =
2137d23d1361SIgor Mitsyanko cpu_to_le32(sme->crypto.ciphers_pairwise[i]);
213898f44cb0SIgor Mitsyanko
2139ecad3b0bSVeerendranath Jakkam n = min(QLINK_MAX_NR_AKM_SUITES, sme->crypto.n_akm_suites);
2140ecad3b0bSVeerendranath Jakkam aen->n_akm_suites = cpu_to_le32(n);
214198f44cb0SIgor Mitsyanko
2142ecad3b0bSVeerendranath Jakkam for (i = 0; i < n; i++)
2143d23d1361SIgor Mitsyanko aen->akm_suites[i] = cpu_to_le32(sme->crypto.akm_suites[i]);
214498f44cb0SIgor Mitsyanko
2145d23d1361SIgor Mitsyanko aen->control_port = sme->crypto.control_port;
2146d23d1361SIgor Mitsyanko aen->control_port_no_encrypt =
21479766d1ddSIgor Mitsyanko sme->crypto.control_port_no_encrypt;
2148d23d1361SIgor Mitsyanko aen->control_port_ethertype =
2149d23d1361SIgor Mitsyanko cpu_to_le16(be16_to_cpu(sme->crypto.control_port_ethertype));
215098f44cb0SIgor Mitsyanko
21519766d1ddSIgor Mitsyanko qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_SSID, sme->ssid,
21529766d1ddSIgor Mitsyanko sme->ssid_len);
215398f44cb0SIgor Mitsyanko
215498f44cb0SIgor Mitsyanko if (sme->ie_len != 0)
215518b7470fSIgor Mitsyanko qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_ASSOC_REQ,
215618b7470fSIgor Mitsyanko sme->ie, sme->ie_len);
215798f44cb0SIgor Mitsyanko
2158c9889671SIgor Mitsyanko if (sme->channel)
2159c9889671SIgor Mitsyanko qtnf_cmd_channel_tlv_add(cmd_skb, sme->channel);
2160c9889671SIgor Mitsyanko
2161d23d1361SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
2162c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
216398f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
2164c6ed298fSSergey Matyukevich
216598f44cb0SIgor Mitsyanko return ret;
216698f44cb0SIgor Mitsyanko }
216798f44cb0SIgor Mitsyanko
qtnf_cmd_send_external_auth(struct qtnf_vif * vif,struct cfg80211_external_auth_params * auth)216847b08e75SSergey Matyukevich int qtnf_cmd_send_external_auth(struct qtnf_vif *vif,
216947b08e75SSergey Matyukevich struct cfg80211_external_auth_params *auth)
217047b08e75SSergey Matyukevich {
217147b08e75SSergey Matyukevich struct sk_buff *cmd_skb;
217247b08e75SSergey Matyukevich struct qlink_cmd_external_auth *cmd;
217347b08e75SSergey Matyukevich int ret;
217447b08e75SSergey Matyukevich
217547b08e75SSergey Matyukevich cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
217647b08e75SSergey Matyukevich QLINK_CMD_EXTERNAL_AUTH,
217747b08e75SSergey Matyukevich sizeof(*cmd));
217847b08e75SSergey Matyukevich if (!cmd_skb)
217947b08e75SSergey Matyukevich return -ENOMEM;
218047b08e75SSergey Matyukevich
218147b08e75SSergey Matyukevich cmd = (struct qlink_cmd_external_auth *)cmd_skb->data;
218247b08e75SSergey Matyukevich
2183b3860e7aSSergey Matyukevich ether_addr_copy(cmd->peer, auth->bssid);
218447b08e75SSergey Matyukevich cmd->status = cpu_to_le16(auth->status);
218547b08e75SSergey Matyukevich
218647b08e75SSergey Matyukevich qtnf_bus_lock(vif->mac->bus);
218747b08e75SSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
218847b08e75SSergey Matyukevich qtnf_bus_unlock(vif->mac->bus);
218947b08e75SSergey Matyukevich
219047b08e75SSergey Matyukevich return ret;
219147b08e75SSergey Matyukevich }
219247b08e75SSergey Matyukevich
qtnf_cmd_send_disconnect(struct qtnf_vif * vif,u16 reason_code)219398f44cb0SIgor Mitsyanko int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code)
219498f44cb0SIgor Mitsyanko {
219598f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
219698f44cb0SIgor Mitsyanko struct qlink_cmd_disconnect *cmd;
219798f44cb0SIgor Mitsyanko int ret;
219898f44cb0SIgor Mitsyanko
219998f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
220098f44cb0SIgor Mitsyanko QLINK_CMD_DISCONNECT,
220198f44cb0SIgor Mitsyanko sizeof(*cmd));
2202c93fe71cSSergey Matyukevich if (!cmd_skb)
220398f44cb0SIgor Mitsyanko return -ENOMEM;
220498f44cb0SIgor Mitsyanko
220598f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
220698f44cb0SIgor Mitsyanko
220798f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_disconnect *)cmd_skb->data;
220898f44cb0SIgor Mitsyanko cmd->reason = cpu_to_le16(reason_code);
220998f44cb0SIgor Mitsyanko
2210c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
221198f44cb0SIgor Mitsyanko
221298f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
2213c6ed298fSSergey Matyukevich
221498f44cb0SIgor Mitsyanko return ret;
221598f44cb0SIgor Mitsyanko }
221698f44cb0SIgor Mitsyanko
qtnf_cmd_send_updown_intf(struct qtnf_vif * vif,bool up)221798f44cb0SIgor Mitsyanko int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up)
221898f44cb0SIgor Mitsyanko {
221998f44cb0SIgor Mitsyanko struct sk_buff *cmd_skb;
222098f44cb0SIgor Mitsyanko struct qlink_cmd_updown *cmd;
222198f44cb0SIgor Mitsyanko int ret;
222298f44cb0SIgor Mitsyanko
222398f44cb0SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
222498f44cb0SIgor Mitsyanko QLINK_CMD_UPDOWN_INTF,
222598f44cb0SIgor Mitsyanko sizeof(*cmd));
2226c93fe71cSSergey Matyukevich if (!cmd_skb)
222798f44cb0SIgor Mitsyanko return -ENOMEM;
222898f44cb0SIgor Mitsyanko
222998f44cb0SIgor Mitsyanko cmd = (struct qlink_cmd_updown *)cmd_skb->data;
223098f44cb0SIgor Mitsyanko cmd->if_up = !!up;
223198f44cb0SIgor Mitsyanko
223298f44cb0SIgor Mitsyanko qtnf_bus_lock(vif->mac->bus);
2233c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
223498f44cb0SIgor Mitsyanko qtnf_bus_unlock(vif->mac->bus);
2235c6ed298fSSergey Matyukevich
223698f44cb0SIgor Mitsyanko return ret;
223798f44cb0SIgor Mitsyanko }
22384dd07d2bSSergey Matyukevich
qtnf_cmd_reg_notify(struct qtnf_wmac * mac,struct regulatory_request * req,bool slave_radar,bool dfs_offload)2239888f1564SIgor Mitsyanko int qtnf_cmd_reg_notify(struct qtnf_wmac *mac, struct regulatory_request *req,
2240155b424cSSergey Matyukevich bool slave_radar, bool dfs_offload)
22414dd07d2bSSergey Matyukevich {
2242a2fbaaf7SIgor Mitsyanko struct wiphy *wiphy = priv_to_wiphy(mac);
2243d1231721SIgor Mitsyanko struct qtnf_bus *bus = mac->bus;
22444dd07d2bSSergey Matyukevich struct sk_buff *cmd_skb;
22454dd07d2bSSergey Matyukevich int ret;
22464dd07d2bSSergey Matyukevich struct qlink_cmd_reg_notify *cmd;
2247a2fbaaf7SIgor Mitsyanko enum nl80211_band band;
2248a2fbaaf7SIgor Mitsyanko const struct ieee80211_supported_band *cfg_band;
22494dd07d2bSSergey Matyukevich
2250d1231721SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
22514dd07d2bSSergey Matyukevich QLINK_CMD_REG_NOTIFY,
22524dd07d2bSSergey Matyukevich sizeof(*cmd));
22534dd07d2bSSergey Matyukevich if (!cmd_skb)
22544dd07d2bSSergey Matyukevich return -ENOMEM;
22554dd07d2bSSergey Matyukevich
22564dd07d2bSSergey Matyukevich cmd = (struct qlink_cmd_reg_notify *)cmd_skb->data;
22574dd07d2bSSergey Matyukevich cmd->alpha2[0] = req->alpha2[0];
22584dd07d2bSSergey Matyukevich cmd->alpha2[1] = req->alpha2[1];
22594dd07d2bSSergey Matyukevich
22604dd07d2bSSergey Matyukevich switch (req->initiator) {
22614dd07d2bSSergey Matyukevich case NL80211_REGDOM_SET_BY_CORE:
22624dd07d2bSSergey Matyukevich cmd->initiator = QLINK_REGDOM_SET_BY_CORE;
22634dd07d2bSSergey Matyukevich break;
22644dd07d2bSSergey Matyukevich case NL80211_REGDOM_SET_BY_USER:
22654dd07d2bSSergey Matyukevich cmd->initiator = QLINK_REGDOM_SET_BY_USER;
22664dd07d2bSSergey Matyukevich break;
22674dd07d2bSSergey Matyukevich case NL80211_REGDOM_SET_BY_DRIVER:
22684dd07d2bSSergey Matyukevich cmd->initiator = QLINK_REGDOM_SET_BY_DRIVER;
22694dd07d2bSSergey Matyukevich break;
22704dd07d2bSSergey Matyukevich case NL80211_REGDOM_SET_BY_COUNTRY_IE:
22714dd07d2bSSergey Matyukevich cmd->initiator = QLINK_REGDOM_SET_BY_COUNTRY_IE;
22724dd07d2bSSergey Matyukevich break;
22734dd07d2bSSergey Matyukevich }
22744dd07d2bSSergey Matyukevich
22754dd07d2bSSergey Matyukevich switch (req->user_reg_hint_type) {
22764dd07d2bSSergey Matyukevich case NL80211_USER_REG_HINT_USER:
22774dd07d2bSSergey Matyukevich cmd->user_reg_hint_type = QLINK_USER_REG_HINT_USER;
22784dd07d2bSSergey Matyukevich break;
22794dd07d2bSSergey Matyukevich case NL80211_USER_REG_HINT_CELL_BASE:
22804dd07d2bSSergey Matyukevich cmd->user_reg_hint_type = QLINK_USER_REG_HINT_CELL_BASE;
22814dd07d2bSSergey Matyukevich break;
22824dd07d2bSSergey Matyukevich case NL80211_USER_REG_HINT_INDOOR:
22834dd07d2bSSergey Matyukevich cmd->user_reg_hint_type = QLINK_USER_REG_HINT_INDOOR;
22844dd07d2bSSergey Matyukevich break;
22854dd07d2bSSergey Matyukevich }
22864dd07d2bSSergey Matyukevich
2287438fb43bSIgor Mitsyanko switch (req->dfs_region) {
2288438fb43bSIgor Mitsyanko case NL80211_DFS_FCC:
2289438fb43bSIgor Mitsyanko cmd->dfs_region = QLINK_DFS_FCC;
2290438fb43bSIgor Mitsyanko break;
2291438fb43bSIgor Mitsyanko case NL80211_DFS_ETSI:
2292438fb43bSIgor Mitsyanko cmd->dfs_region = QLINK_DFS_ETSI;
2293438fb43bSIgor Mitsyanko break;
2294438fb43bSIgor Mitsyanko case NL80211_DFS_JP:
2295438fb43bSIgor Mitsyanko cmd->dfs_region = QLINK_DFS_JP;
2296438fb43bSIgor Mitsyanko break;
2297438fb43bSIgor Mitsyanko default:
2298438fb43bSIgor Mitsyanko cmd->dfs_region = QLINK_DFS_UNSET;
2299438fb43bSIgor Mitsyanko break;
2300438fb43bSIgor Mitsyanko }
2301438fb43bSIgor Mitsyanko
2302888f1564SIgor Mitsyanko cmd->slave_radar = slave_radar;
2303155b424cSSergey Matyukevich cmd->dfs_offload = dfs_offload;
2304a2fbaaf7SIgor Mitsyanko cmd->num_channels = 0;
2305a2fbaaf7SIgor Mitsyanko
2306a2fbaaf7SIgor Mitsyanko for (band = 0; band < NUM_NL80211_BANDS; band++) {
2307a2fbaaf7SIgor Mitsyanko unsigned int i;
2308a2fbaaf7SIgor Mitsyanko
2309a2fbaaf7SIgor Mitsyanko cfg_band = wiphy->bands[band];
2310a2fbaaf7SIgor Mitsyanko if (!cfg_band)
2311a2fbaaf7SIgor Mitsyanko continue;
2312a2fbaaf7SIgor Mitsyanko
2313a2fbaaf7SIgor Mitsyanko cmd->num_channels += cfg_band->n_channels;
2314a2fbaaf7SIgor Mitsyanko
2315a2fbaaf7SIgor Mitsyanko for (i = 0; i < cfg_band->n_channels; ++i) {
2316a2fbaaf7SIgor Mitsyanko qtnf_cmd_channel_tlv_add(cmd_skb,
2317a2fbaaf7SIgor Mitsyanko &cfg_band->channels[i]);
2318a2fbaaf7SIgor Mitsyanko }
2319a2fbaaf7SIgor Mitsyanko }
2320a2fbaaf7SIgor Mitsyanko
23214dd07d2bSSergey Matyukevich qtnf_bus_lock(bus);
2322c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(bus, cmd_skb);
23234dd07d2bSSergey Matyukevich qtnf_bus_unlock(bus);
23244dd07d2bSSergey Matyukevich
23254dd07d2bSSergey Matyukevich return ret;
23264dd07d2bSSergey Matyukevich }
23277c04b439SSergey Matyukevich
2328601ce21fSIgor Mitsyanko static int
qtnf_cmd_resp_proc_chan_stat_info(struct survey_info * survey,const u8 * payload,size_t payload_len)2329601ce21fSIgor Mitsyanko qtnf_cmd_resp_proc_chan_stat_info(struct survey_info *survey,
2330601ce21fSIgor Mitsyanko const u8 *payload, size_t payload_len)
2331601ce21fSIgor Mitsyanko {
2332601ce21fSIgor Mitsyanko const struct qlink_chan_stats *stats = NULL;
2333601ce21fSIgor Mitsyanko const struct qlink_tlv_hdr *tlv;
2334601ce21fSIgor Mitsyanko u16 tlv_value_len;
2335601ce21fSIgor Mitsyanko u16 tlv_type;
2336601ce21fSIgor Mitsyanko const u8 *map = NULL;
2337601ce21fSIgor Mitsyanko unsigned int map_len = 0;
2338601ce21fSIgor Mitsyanko unsigned int stats_len = 0;
2339601ce21fSIgor Mitsyanko
23408b0b5f1bSIgor Mitsyanko qlink_for_each_tlv(tlv, payload, payload_len) {
2341601ce21fSIgor Mitsyanko tlv_type = le16_to_cpu(tlv->type);
2342601ce21fSIgor Mitsyanko tlv_value_len = le16_to_cpu(tlv->len);
2343601ce21fSIgor Mitsyanko
2344601ce21fSIgor Mitsyanko switch (tlv_type) {
2345601ce21fSIgor Mitsyanko case QTN_TLV_ID_BITMAP:
2346601ce21fSIgor Mitsyanko map = tlv->val;
2347601ce21fSIgor Mitsyanko map_len = tlv_value_len;
2348601ce21fSIgor Mitsyanko break;
2349601ce21fSIgor Mitsyanko case QTN_TLV_ID_CHANNEL_STATS:
2350601ce21fSIgor Mitsyanko stats = (struct qlink_chan_stats *)tlv->val;
2351601ce21fSIgor Mitsyanko stats_len = tlv_value_len;
2352601ce21fSIgor Mitsyanko break;
2353601ce21fSIgor Mitsyanko default:
2354601ce21fSIgor Mitsyanko pr_info("Unknown TLV type: %#x\n", tlv_type);
2355601ce21fSIgor Mitsyanko break;
2356601ce21fSIgor Mitsyanko }
2357601ce21fSIgor Mitsyanko }
2358601ce21fSIgor Mitsyanko
23598b0b5f1bSIgor Mitsyanko if (!qlink_tlv_parsing_ok(tlv, payload, payload_len)) {
23608b0b5f1bSIgor Mitsyanko pr_err("Malformed TLV buffer\n");
2361601ce21fSIgor Mitsyanko return -EINVAL;
2362601ce21fSIgor Mitsyanko }
2363601ce21fSIgor Mitsyanko
2364601ce21fSIgor Mitsyanko if (!map || !stats)
2365601ce21fSIgor Mitsyanko return 0;
2366601ce21fSIgor Mitsyanko
2367601ce21fSIgor Mitsyanko #define qtnf_chan_stat_avail(stat_name, bitn) \
2368601ce21fSIgor Mitsyanko (qtnf_utils_is_bit_set(map, bitn, map_len) && \
2369601ce21fSIgor Mitsyanko (offsetofend(struct qlink_chan_stats, stat_name) <= stats_len))
2370601ce21fSIgor Mitsyanko
2371601ce21fSIgor Mitsyanko if (qtnf_chan_stat_avail(time_on, QLINK_CHAN_STAT_TIME_ON)) {
2372601ce21fSIgor Mitsyanko survey->filled |= SURVEY_INFO_TIME;
2373601ce21fSIgor Mitsyanko survey->time = le64_to_cpu(stats->time_on);
2374601ce21fSIgor Mitsyanko }
2375601ce21fSIgor Mitsyanko
2376601ce21fSIgor Mitsyanko if (qtnf_chan_stat_avail(time_tx, QLINK_CHAN_STAT_TIME_TX)) {
2377601ce21fSIgor Mitsyanko survey->filled |= SURVEY_INFO_TIME_TX;
2378601ce21fSIgor Mitsyanko survey->time_tx = le64_to_cpu(stats->time_tx);
2379601ce21fSIgor Mitsyanko }
2380601ce21fSIgor Mitsyanko
2381601ce21fSIgor Mitsyanko if (qtnf_chan_stat_avail(time_rx, QLINK_CHAN_STAT_TIME_RX)) {
2382601ce21fSIgor Mitsyanko survey->filled |= SURVEY_INFO_TIME_RX;
2383601ce21fSIgor Mitsyanko survey->time_rx = le64_to_cpu(stats->time_rx);
2384601ce21fSIgor Mitsyanko }
2385601ce21fSIgor Mitsyanko
2386601ce21fSIgor Mitsyanko if (qtnf_chan_stat_avail(cca_busy, QLINK_CHAN_STAT_CCA_BUSY)) {
2387601ce21fSIgor Mitsyanko survey->filled |= SURVEY_INFO_TIME_BUSY;
2388601ce21fSIgor Mitsyanko survey->time_busy = le64_to_cpu(stats->cca_busy);
2389601ce21fSIgor Mitsyanko }
2390601ce21fSIgor Mitsyanko
2391601ce21fSIgor Mitsyanko if (qtnf_chan_stat_avail(cca_busy_ext, QLINK_CHAN_STAT_CCA_BUSY_EXT)) {
2392601ce21fSIgor Mitsyanko survey->filled |= SURVEY_INFO_TIME_EXT_BUSY;
2393601ce21fSIgor Mitsyanko survey->time_ext_busy = le64_to_cpu(stats->cca_busy_ext);
2394601ce21fSIgor Mitsyanko }
2395601ce21fSIgor Mitsyanko
2396601ce21fSIgor Mitsyanko if (qtnf_chan_stat_avail(time_scan, QLINK_CHAN_STAT_TIME_SCAN)) {
2397601ce21fSIgor Mitsyanko survey->filled |= SURVEY_INFO_TIME_SCAN;
2398601ce21fSIgor Mitsyanko survey->time_scan = le64_to_cpu(stats->time_scan);
2399601ce21fSIgor Mitsyanko }
2400601ce21fSIgor Mitsyanko
2401601ce21fSIgor Mitsyanko if (qtnf_chan_stat_avail(chan_noise, QLINK_CHAN_STAT_CHAN_NOISE)) {
2402601ce21fSIgor Mitsyanko survey->filled |= SURVEY_INFO_NOISE_DBM;
2403601ce21fSIgor Mitsyanko survey->noise = stats->chan_noise;
2404601ce21fSIgor Mitsyanko }
2405601ce21fSIgor Mitsyanko
2406601ce21fSIgor Mitsyanko #undef qtnf_chan_stat_avail
2407601ce21fSIgor Mitsyanko
2408601ce21fSIgor Mitsyanko return 0;
2409601ce21fSIgor Mitsyanko }
2410601ce21fSIgor Mitsyanko
qtnf_cmd_get_chan_stats(struct qtnf_wmac * mac,u32 chan_freq,struct survey_info * survey)2411601ce21fSIgor Mitsyanko int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u32 chan_freq,
2412601ce21fSIgor Mitsyanko struct survey_info *survey)
24137c04b439SSergey Matyukevich {
24147c04b439SSergey Matyukevich struct sk_buff *cmd_skb, *resp_skb = NULL;
24157c04b439SSergey Matyukevich struct qlink_cmd_get_chan_stats *cmd;
24167c04b439SSergey Matyukevich struct qlink_resp_get_chan_stats *resp;
24171066bd19SSergey Matyukevich size_t var_data_len = 0;
24187c04b439SSergey Matyukevich int ret = 0;
24197c04b439SSergey Matyukevich
24207c04b439SSergey Matyukevich cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
24217c04b439SSergey Matyukevich QLINK_CMD_CHAN_STATS,
24227c04b439SSergey Matyukevich sizeof(*cmd));
24237c04b439SSergey Matyukevich if (!cmd_skb)
24247c04b439SSergey Matyukevich return -ENOMEM;
24257c04b439SSergey Matyukevich
24267c04b439SSergey Matyukevich cmd = (struct qlink_cmd_get_chan_stats *)cmd_skb->data;
2427601ce21fSIgor Mitsyanko cmd->channel_freq = cpu_to_le32(chan_freq);
24287c04b439SSergey Matyukevich
2429601ce21fSIgor Mitsyanko qtnf_bus_lock(mac->bus);
2430c6ed298fSSergey Matyukevich ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,
24317c04b439SSergey Matyukevich sizeof(*resp), &var_data_len);
2432601ce21fSIgor Mitsyanko qtnf_bus_unlock(mac->bus);
2433601ce21fSIgor Mitsyanko
2434c6ed298fSSergey Matyukevich if (ret)
24357c04b439SSergey Matyukevich goto out;
24367c04b439SSergey Matyukevich
24377c04b439SSergey Matyukevich resp = (struct qlink_resp_get_chan_stats *)resp_skb->data;
2438601ce21fSIgor Mitsyanko
2439601ce21fSIgor Mitsyanko if (le32_to_cpu(resp->chan_freq) != chan_freq) {
2440601ce21fSIgor Mitsyanko pr_err("[MAC%u] channel stats freq %u != requested %u\n",
2441601ce21fSIgor Mitsyanko mac->macid, le32_to_cpu(resp->chan_freq), chan_freq);
2442601ce21fSIgor Mitsyanko ret = -EINVAL;
2443601ce21fSIgor Mitsyanko goto out;
2444601ce21fSIgor Mitsyanko }
2445601ce21fSIgor Mitsyanko
2446601ce21fSIgor Mitsyanko ret = qtnf_cmd_resp_proc_chan_stat_info(survey, resp->info,
24477c04b439SSergey Matyukevich var_data_len);
24487c04b439SSergey Matyukevich
24497c04b439SSergey Matyukevich out:
24507c04b439SSergey Matyukevich consume_skb(resp_skb);
2451c6ed298fSSergey Matyukevich
24527c04b439SSergey Matyukevich return ret;
24537c04b439SSergey Matyukevich }
245497883695SSergey Matyukevich
qtnf_cmd_send_chan_switch(struct qtnf_vif * vif,struct cfg80211_csa_settings * params)24558c015b90SIgor Mitsyanko int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,
245697883695SSergey Matyukevich struct cfg80211_csa_settings *params)
245797883695SSergey Matyukevich {
24588c015b90SIgor Mitsyanko struct qtnf_wmac *mac = vif->mac;
245997883695SSergey Matyukevich struct qlink_cmd_chan_switch *cmd;
246097883695SSergey Matyukevich struct sk_buff *cmd_skb;
246197883695SSergey Matyukevich int ret;
24625edadc5aSIgor Mitsyanko u64 flags = 0;
246397883695SSergey Matyukevich
24648c015b90SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid,
246597883695SSergey Matyukevich QLINK_CMD_CHAN_SWITCH,
246697883695SSergey Matyukevich sizeof(*cmd));
2467c93fe71cSSergey Matyukevich if (!cmd_skb)
246897883695SSergey Matyukevich return -ENOMEM;
246997883695SSergey Matyukevich
24705edadc5aSIgor Mitsyanko if (params->radar_required)
24715edadc5aSIgor Mitsyanko flags |= QLINK_CHAN_SW_RADAR_REQUIRED;
24725edadc5aSIgor Mitsyanko
24735edadc5aSIgor Mitsyanko if (params->block_tx)
24745edadc5aSIgor Mitsyanko flags |= QLINK_CHAN_SW_BLOCK_TX;
247597883695SSergey Matyukevich
247697883695SSergey Matyukevich cmd = (struct qlink_cmd_chan_switch *)cmd_skb->data;
24775edadc5aSIgor Mitsyanko qlink_chandef_cfg2q(¶ms->chandef, &cmd->channel);
24785edadc5aSIgor Mitsyanko cmd->flags = cpu_to_le64(flags);
247997883695SSergey Matyukevich cmd->beacon_count = params->count;
248097883695SSergey Matyukevich
24815edadc5aSIgor Mitsyanko qtnf_bus_lock(mac->bus);
2482c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(mac->bus, cmd_skb);
248397883695SSergey Matyukevich qtnf_bus_unlock(mac->bus);
2484c6ed298fSSergey Matyukevich
248597883695SSergey Matyukevich return ret;
248697883695SSergey Matyukevich }
24879e5478b6SIgor Mitsyanko
qtnf_cmd_get_channel(struct qtnf_vif * vif,struct cfg80211_chan_def * chdef)24889e5478b6SIgor Mitsyanko int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)
24899e5478b6SIgor Mitsyanko {
24909e5478b6SIgor Mitsyanko struct qtnf_bus *bus = vif->mac->bus;
24919e5478b6SIgor Mitsyanko const struct qlink_resp_channel_get *resp;
24929e5478b6SIgor Mitsyanko struct sk_buff *cmd_skb;
24939e5478b6SIgor Mitsyanko struct sk_buff *resp_skb = NULL;
24949e5478b6SIgor Mitsyanko int ret;
24959e5478b6SIgor Mitsyanko
24969e5478b6SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
24979e5478b6SIgor Mitsyanko QLINK_CMD_CHAN_GET,
24989e5478b6SIgor Mitsyanko sizeof(struct qlink_cmd));
2499c93fe71cSSergey Matyukevich if (!cmd_skb)
25009e5478b6SIgor Mitsyanko return -ENOMEM;
25019e5478b6SIgor Mitsyanko
25029e5478b6SIgor Mitsyanko qtnf_bus_lock(bus);
2503c6ed298fSSergey Matyukevich ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,
25049e5478b6SIgor Mitsyanko sizeof(*resp), NULL);
2505c6ed298fSSergey Matyukevich if (ret)
25069e5478b6SIgor Mitsyanko goto out;
25079e5478b6SIgor Mitsyanko
25089e5478b6SIgor Mitsyanko resp = (const struct qlink_resp_channel_get *)resp_skb->data;
25099e5478b6SIgor Mitsyanko qlink_chandef_q2cfg(priv_to_wiphy(vif->mac), &resp->chan, chdef);
25109e5478b6SIgor Mitsyanko
25119e5478b6SIgor Mitsyanko out:
2512c6ed298fSSergey Matyukevich qtnf_bus_unlock(bus);
25139e5478b6SIgor Mitsyanko consume_skb(resp_skb);
2514c6ed298fSSergey Matyukevich
25159e5478b6SIgor Mitsyanko return ret;
25169e5478b6SIgor Mitsyanko }
2517b05ee456SIgor Mitsyanko
qtnf_cmd_start_cac(const struct qtnf_vif * vif,const struct cfg80211_chan_def * chdef,u32 cac_time_ms)2518b05ee456SIgor Mitsyanko int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
2519b05ee456SIgor Mitsyanko const struct cfg80211_chan_def *chdef,
2520b05ee456SIgor Mitsyanko u32 cac_time_ms)
2521b05ee456SIgor Mitsyanko {
2522b05ee456SIgor Mitsyanko struct qtnf_bus *bus = vif->mac->bus;
2523b05ee456SIgor Mitsyanko struct sk_buff *cmd_skb;
2524b05ee456SIgor Mitsyanko struct qlink_cmd_start_cac *cmd;
2525b05ee456SIgor Mitsyanko int ret;
2526b05ee456SIgor Mitsyanko
2527b05ee456SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
2528b05ee456SIgor Mitsyanko QLINK_CMD_START_CAC,
2529b05ee456SIgor Mitsyanko sizeof(*cmd));
2530c93fe71cSSergey Matyukevich if (!cmd_skb)
2531b05ee456SIgor Mitsyanko return -ENOMEM;
2532b05ee456SIgor Mitsyanko
2533b05ee456SIgor Mitsyanko cmd = (struct qlink_cmd_start_cac *)cmd_skb->data;
2534b05ee456SIgor Mitsyanko cmd->cac_time_ms = cpu_to_le32(cac_time_ms);
2535b05ee456SIgor Mitsyanko qlink_chandef_cfg2q(chdef, &cmd->chan);
2536b05ee456SIgor Mitsyanko
2537b05ee456SIgor Mitsyanko qtnf_bus_lock(bus);
2538c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(bus, cmd_skb);
2539c6ed298fSSergey Matyukevich qtnf_bus_unlock(bus);
2540b05ee456SIgor Mitsyanko
2541b05ee456SIgor Mitsyanko return ret;
2542b05ee456SIgor Mitsyanko }
2543f1398fd2SVasily Ulyanov
qtnf_cmd_set_mac_acl(const struct qtnf_vif * vif,const struct cfg80211_acl_data * params)2544f1398fd2SVasily Ulyanov int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,
2545f1398fd2SVasily Ulyanov const struct cfg80211_acl_data *params)
2546f1398fd2SVasily Ulyanov {
2547f1398fd2SVasily Ulyanov struct qtnf_bus *bus = vif->mac->bus;
2548f1398fd2SVasily Ulyanov struct sk_buff *cmd_skb;
254933f98992SVasily Ulyanov struct qlink_tlv_hdr *tlv;
255095336d4cSGustavo A. R. Silva size_t acl_size = struct_size(params, mac_addrs, params->n_acl_entries);
2551f1398fd2SVasily Ulyanov int ret;
2552f1398fd2SVasily Ulyanov
2553f1398fd2SVasily Ulyanov cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
2554f1398fd2SVasily Ulyanov QLINK_CMD_SET_MAC_ACL,
255533f98992SVasily Ulyanov sizeof(struct qlink_cmd));
2556c93fe71cSSergey Matyukevich if (!cmd_skb)
2557f1398fd2SVasily Ulyanov return -ENOMEM;
2558f1398fd2SVasily Ulyanov
25598b0b5f1bSIgor Mitsyanko tlv = skb_put(cmd_skb, sizeof(*tlv) + round_up(acl_size, QLINK_ALIGN));
256033f98992SVasily Ulyanov tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA);
256133f98992SVasily Ulyanov tlv->len = cpu_to_le16(acl_size);
256233f98992SVasily Ulyanov qlink_acl_data_cfg2q(params, (struct qlink_acl_data *)tlv->val);
2563f1398fd2SVasily Ulyanov
2564f1398fd2SVasily Ulyanov qtnf_bus_lock(bus);
2565c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(bus, cmd_skb);
2566f1398fd2SVasily Ulyanov qtnf_bus_unlock(bus);
2567f1398fd2SVasily Ulyanov
2568f1398fd2SVasily Ulyanov return ret;
2569f1398fd2SVasily Ulyanov }
25704775ad06SSergei Maksimenko
qtnf_cmd_send_pm_set(const struct qtnf_vif * vif,u8 pm_mode,int timeout)25714775ad06SSergei Maksimenko int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout)
25724775ad06SSergei Maksimenko {
25734775ad06SSergei Maksimenko struct qtnf_bus *bus = vif->mac->bus;
25744775ad06SSergei Maksimenko struct sk_buff *cmd_skb;
25754775ad06SSergei Maksimenko struct qlink_cmd_pm_set *cmd;
25764775ad06SSergei Maksimenko int ret = 0;
25774775ad06SSergei Maksimenko
25784775ad06SSergei Maksimenko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
25794775ad06SSergei Maksimenko QLINK_CMD_PM_SET, sizeof(*cmd));
25804775ad06SSergei Maksimenko if (!cmd_skb)
25814775ad06SSergei Maksimenko return -ENOMEM;
25824775ad06SSergei Maksimenko
25834775ad06SSergei Maksimenko cmd = (struct qlink_cmd_pm_set *)cmd_skb->data;
25844775ad06SSergei Maksimenko cmd->pm_mode = pm_mode;
25854775ad06SSergei Maksimenko cmd->pm_standby_timer = cpu_to_le32(timeout);
25864775ad06SSergei Maksimenko
25874775ad06SSergei Maksimenko qtnf_bus_lock(bus);
25884775ad06SSergei Maksimenko
2589c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(bus, cmd_skb);
25904775ad06SSergei Maksimenko
25914775ad06SSergei Maksimenko qtnf_bus_unlock(bus);
2592c6ed298fSSergey Matyukevich
25934775ad06SSergei Maksimenko return ret;
25944775ad06SSergei Maksimenko }
259528b91884SSergey Matyukevich
qtnf_cmd_get_tx_power(const struct qtnf_vif * vif,int * dbm)25960756e913SMikhail Karpenko int qtnf_cmd_get_tx_power(const struct qtnf_vif *vif, int *dbm)
25970756e913SMikhail Karpenko {
25980756e913SMikhail Karpenko struct qtnf_bus *bus = vif->mac->bus;
25990756e913SMikhail Karpenko const struct qlink_resp_txpwr *resp;
26000756e913SMikhail Karpenko struct sk_buff *resp_skb = NULL;
26010756e913SMikhail Karpenko struct qlink_cmd_txpwr *cmd;
26020756e913SMikhail Karpenko struct sk_buff *cmd_skb;
26030756e913SMikhail Karpenko int ret = 0;
26040756e913SMikhail Karpenko
26050756e913SMikhail Karpenko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
26060756e913SMikhail Karpenko QLINK_CMD_TXPWR, sizeof(*cmd));
26070756e913SMikhail Karpenko if (!cmd_skb)
26080756e913SMikhail Karpenko return -ENOMEM;
26090756e913SMikhail Karpenko
26100756e913SMikhail Karpenko cmd = (struct qlink_cmd_txpwr *)cmd_skb->data;
26110756e913SMikhail Karpenko cmd->op_type = QLINK_TXPWR_GET;
26120756e913SMikhail Karpenko
26130756e913SMikhail Karpenko qtnf_bus_lock(bus);
26140756e913SMikhail Karpenko
26150756e913SMikhail Karpenko ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,
26160756e913SMikhail Karpenko sizeof(*resp), NULL);
26170756e913SMikhail Karpenko if (ret)
26180756e913SMikhail Karpenko goto out;
26190756e913SMikhail Karpenko
26200756e913SMikhail Karpenko resp = (const struct qlink_resp_txpwr *)resp_skb->data;
26210756e913SMikhail Karpenko *dbm = MBM_TO_DBM(le32_to_cpu(resp->txpwr));
26220756e913SMikhail Karpenko
26230756e913SMikhail Karpenko out:
26240756e913SMikhail Karpenko qtnf_bus_unlock(bus);
26250756e913SMikhail Karpenko consume_skb(resp_skb);
26260756e913SMikhail Karpenko
26270756e913SMikhail Karpenko return ret;
26280756e913SMikhail Karpenko }
26290756e913SMikhail Karpenko
qtnf_cmd_set_tx_power(const struct qtnf_vif * vif,enum nl80211_tx_power_setting type,int mbm)26300756e913SMikhail Karpenko int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif,
26310756e913SMikhail Karpenko enum nl80211_tx_power_setting type, int mbm)
26320756e913SMikhail Karpenko {
26330756e913SMikhail Karpenko struct qtnf_bus *bus = vif->mac->bus;
26340756e913SMikhail Karpenko const struct qlink_resp_txpwr *resp;
26350756e913SMikhail Karpenko struct sk_buff *resp_skb = NULL;
26360756e913SMikhail Karpenko struct qlink_cmd_txpwr *cmd;
26370756e913SMikhail Karpenko struct sk_buff *cmd_skb;
26380756e913SMikhail Karpenko int ret = 0;
26390756e913SMikhail Karpenko
26400756e913SMikhail Karpenko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
26410756e913SMikhail Karpenko QLINK_CMD_TXPWR, sizeof(*cmd));
26420756e913SMikhail Karpenko if (!cmd_skb)
26430756e913SMikhail Karpenko return -ENOMEM;
26440756e913SMikhail Karpenko
26450756e913SMikhail Karpenko cmd = (struct qlink_cmd_txpwr *)cmd_skb->data;
26460756e913SMikhail Karpenko cmd->op_type = QLINK_TXPWR_SET;
26470756e913SMikhail Karpenko cmd->txpwr_setting = type;
26480756e913SMikhail Karpenko cmd->txpwr = cpu_to_le32(mbm);
26490756e913SMikhail Karpenko
26500756e913SMikhail Karpenko qtnf_bus_lock(bus);
26510756e913SMikhail Karpenko
26520756e913SMikhail Karpenko ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,
26530756e913SMikhail Karpenko sizeof(*resp), NULL);
26540756e913SMikhail Karpenko
26550756e913SMikhail Karpenko qtnf_bus_unlock(bus);
26560756e913SMikhail Karpenko consume_skb(resp_skb);
26570756e913SMikhail Karpenko
26580756e913SMikhail Karpenko return ret;
26590756e913SMikhail Karpenko }
26600756e913SMikhail Karpenko
qtnf_cmd_send_wowlan_set(const struct qtnf_vif * vif,const struct cfg80211_wowlan * wowl)266128b91884SSergey Matyukevich int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif,
266228b91884SSergey Matyukevich const struct cfg80211_wowlan *wowl)
266328b91884SSergey Matyukevich {
266428b91884SSergey Matyukevich struct qtnf_bus *bus = vif->mac->bus;
266528b91884SSergey Matyukevich struct sk_buff *cmd_skb;
266628b91884SSergey Matyukevich struct qlink_cmd_wowlan_set *cmd;
266728b91884SSergey Matyukevich u32 triggers = 0;
266828b91884SSergey Matyukevich int count = 0;
266928b91884SSergey Matyukevich int ret = 0;
267028b91884SSergey Matyukevich
267128b91884SSergey Matyukevich cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
267228b91884SSergey Matyukevich QLINK_CMD_WOWLAN_SET, sizeof(*cmd));
267328b91884SSergey Matyukevich if (!cmd_skb)
267428b91884SSergey Matyukevich return -ENOMEM;
267528b91884SSergey Matyukevich
267628b91884SSergey Matyukevich qtnf_bus_lock(bus);
267728b91884SSergey Matyukevich
267828b91884SSergey Matyukevich cmd = (struct qlink_cmd_wowlan_set *)cmd_skb->data;
267928b91884SSergey Matyukevich
268028b91884SSergey Matyukevich if (wowl) {
268128b91884SSergey Matyukevich if (wowl->disconnect)
268228b91884SSergey Matyukevich triggers |= QLINK_WOWLAN_TRIG_DISCONNECT;
268328b91884SSergey Matyukevich
268428b91884SSergey Matyukevich if (wowl->magic_pkt)
268528b91884SSergey Matyukevich triggers |= QLINK_WOWLAN_TRIG_MAGIC_PKT;
268628b91884SSergey Matyukevich
268728b91884SSergey Matyukevich if (wowl->n_patterns && wowl->patterns) {
268828b91884SSergey Matyukevich triggers |= QLINK_WOWLAN_TRIG_PATTERN_PKT;
268928b91884SSergey Matyukevich while (count < wowl->n_patterns) {
269028b91884SSergey Matyukevich qtnf_cmd_skb_put_tlv_arr(cmd_skb,
269128b91884SSergey Matyukevich QTN_TLV_ID_WOWLAN_PATTERN,
269228b91884SSergey Matyukevich wowl->patterns[count].pattern,
269328b91884SSergey Matyukevich wowl->patterns[count].pattern_len);
269428b91884SSergey Matyukevich count++;
269528b91884SSergey Matyukevich }
269628b91884SSergey Matyukevich }
269728b91884SSergey Matyukevich }
269828b91884SSergey Matyukevich
269928b91884SSergey Matyukevich cmd->triggers = cpu_to_le32(triggers);
270028b91884SSergey Matyukevich
2701c6ed298fSSergey Matyukevich ret = qtnf_cmd_send(bus, cmd_skb);
270228b91884SSergey Matyukevich
270328b91884SSergey Matyukevich qtnf_bus_unlock(bus);
270428b91884SSergey Matyukevich return ret;
270528b91884SSergey Matyukevich }
2706decfc5c7SIgor Mitsyanko
qtnf_cmd_netdev_changeupper(const struct qtnf_vif * vif,int br_domain)2707decfc5c7SIgor Mitsyanko int qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain)
2708decfc5c7SIgor Mitsyanko {
2709decfc5c7SIgor Mitsyanko struct qtnf_bus *bus = vif->mac->bus;
2710decfc5c7SIgor Mitsyanko struct sk_buff *cmd_skb;
2711decfc5c7SIgor Mitsyanko struct qlink_cmd_ndev_changeupper *cmd;
2712decfc5c7SIgor Mitsyanko int ret;
2713decfc5c7SIgor Mitsyanko
2714decfc5c7SIgor Mitsyanko cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
2715decfc5c7SIgor Mitsyanko QLINK_CMD_NDEV_EVENT,
2716decfc5c7SIgor Mitsyanko sizeof(*cmd));
2717decfc5c7SIgor Mitsyanko if (!cmd_skb)
2718decfc5c7SIgor Mitsyanko return -ENOMEM;
2719decfc5c7SIgor Mitsyanko
2720decfc5c7SIgor Mitsyanko pr_debug("[VIF%u.%u] set broadcast domain to %d\n",
2721decfc5c7SIgor Mitsyanko vif->mac->macid, vif->vifid, br_domain);
2722decfc5c7SIgor Mitsyanko
2723decfc5c7SIgor Mitsyanko cmd = (struct qlink_cmd_ndev_changeupper *)cmd_skb->data;
2724decfc5c7SIgor Mitsyanko cmd->nehdr.event = cpu_to_le16(QLINK_NDEV_EVENT_CHANGEUPPER);
2725decfc5c7SIgor Mitsyanko cmd->upper_type = QLINK_NDEV_UPPER_TYPE_BRIDGE;
2726decfc5c7SIgor Mitsyanko cmd->br_domain = cpu_to_le32(br_domain);
2727decfc5c7SIgor Mitsyanko
2728decfc5c7SIgor Mitsyanko qtnf_bus_lock(bus);
2729decfc5c7SIgor Mitsyanko ret = qtnf_cmd_send(bus, cmd_skb);
2730decfc5c7SIgor Mitsyanko qtnf_bus_unlock(bus);
2731decfc5c7SIgor Mitsyanko
2732decfc5c7SIgor Mitsyanko if (ret)
2733decfc5c7SIgor Mitsyanko pr_err("[VIF%u.%u] failed to set broadcast domain\n",
2734decfc5c7SIgor Mitsyanko vif->mac->macid, vif->vifid);
2735decfc5c7SIgor Mitsyanko
2736decfc5c7SIgor Mitsyanko return ret;
2737decfc5c7SIgor Mitsyanko }
273844d09764SSergey Matyukevich
qtnf_cmd_send_update_owe(struct qtnf_vif * vif,struct cfg80211_update_owe_info * owe)273944d09764SSergey Matyukevich int qtnf_cmd_send_update_owe(struct qtnf_vif *vif,
274044d09764SSergey Matyukevich struct cfg80211_update_owe_info *owe)
274144d09764SSergey Matyukevich {
274244d09764SSergey Matyukevich struct qlink_cmd_update_owe *cmd;
274344d09764SSergey Matyukevich struct sk_buff *cmd_skb;
274444d09764SSergey Matyukevich int ret;
274544d09764SSergey Matyukevich
274644d09764SSergey Matyukevich if (sizeof(*cmd) + owe->ie_len > QTNF_MAX_CMD_BUF_SIZE) {
274744d09764SSergey Matyukevich pr_warn("VIF%u.%u: OWE update IEs too big: %zu\n",
274844d09764SSergey Matyukevich vif->mac->macid, vif->vifid, owe->ie_len);
274944d09764SSergey Matyukevich return -E2BIG;
275044d09764SSergey Matyukevich }
275144d09764SSergey Matyukevich
275244d09764SSergey Matyukevich cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
275344d09764SSergey Matyukevich QLINK_CMD_UPDATE_OWE,
275444d09764SSergey Matyukevich sizeof(*cmd));
275544d09764SSergey Matyukevich if (!cmd_skb)
275644d09764SSergey Matyukevich return -ENOMEM;
275744d09764SSergey Matyukevich
275844d09764SSergey Matyukevich cmd = (struct qlink_cmd_update_owe *)cmd_skb->data;
275944d09764SSergey Matyukevich ether_addr_copy(cmd->peer, owe->peer);
276044d09764SSergey Matyukevich cmd->status = cpu_to_le16(owe->status);
276144d09764SSergey Matyukevich if (owe->ie_len && owe->ie)
276244d09764SSergey Matyukevich qtnf_cmd_skb_put_buffer(cmd_skb, owe->ie, owe->ie_len);
276344d09764SSergey Matyukevich
276444d09764SSergey Matyukevich qtnf_bus_lock(vif->mac->bus);
276544d09764SSergey Matyukevich ret = qtnf_cmd_send(vif->mac->bus, cmd_skb);
276644d09764SSergey Matyukevich qtnf_bus_unlock(vif->mac->bus);
276744d09764SSergey Matyukevich
276844d09764SSergey Matyukevich return ret;
276944d09764SSergey Matyukevich }
2770