|
@@ -1115,19 +1115,50 @@ qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac,
|
|
|
sizeof(mac_info->vht_cap));
|
|
|
}
|
|
|
|
|
|
+static void qtnf_cmd_resp_band_fill_htcap(const u8 *info,
|
|
|
+ struct ieee80211_sta_ht_cap *bcap)
|
|
|
+{
|
|
|
+ const struct ieee80211_ht_cap *ht_cap =
|
|
|
+ (const struct ieee80211_ht_cap *)info;
|
|
|
+
|
|
|
+ bcap->ht_supported = true;
|
|
|
+ bcap->cap = le16_to_cpu(ht_cap->cap_info);
|
|
|
+ bcap->ampdu_factor =
|
|
|
+ ht_cap->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
|
|
|
+ bcap->ampdu_density =
|
|
|
+ (ht_cap->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >>
|
|
|
+ IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT;
|
|
|
+ memcpy(&bcap->mcs, &ht_cap->mcs, sizeof(bcap->mcs));
|
|
|
+}
|
|
|
+
|
|
|
+static void qtnf_cmd_resp_band_fill_vhtcap(const u8 *info,
|
|
|
+ struct ieee80211_sta_vht_cap *bcap)
|
|
|
+{
|
|
|
+ const struct ieee80211_vht_cap *vht_cap =
|
|
|
+ (const struct ieee80211_vht_cap *)info;
|
|
|
+
|
|
|
+ bcap->vht_supported = true;
|
|
|
+ bcap->cap = le32_to_cpu(vht_cap->vht_cap_info);
|
|
|
+ memcpy(&bcap->vht_mcs, &vht_cap->supp_mcs, sizeof(bcap->vht_mcs));
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
-qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band,
|
|
|
- struct qlink_resp_get_chan_info *resp,
|
|
|
- size_t payload_len)
|
|
|
+qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
|
|
|
+ struct qlink_resp_band_info_get *resp,
|
|
|
+ size_t payload_len)
|
|
|
{
|
|
|
u16 tlv_type;
|
|
|
size_t tlv_len;
|
|
|
+ size_t tlv_dlen;
|
|
|
const struct qlink_tlv_hdr *tlv;
|
|
|
const struct qlink_tlv_channel *qchan;
|
|
|
struct ieee80211_channel *chan;
|
|
|
unsigned int chidx = 0;
|
|
|
u32 qflags;
|
|
|
|
|
|
+ memset(&band->ht_cap, 0, sizeof(band->ht_cap));
|
|
|
+ memset(&band->vht_cap, 0, sizeof(band->vht_cap));
|
|
|
+
|
|
|
if (band->channels) {
|
|
|
if (band->n_channels == resp->num_chans) {
|
|
|
memset(band->channels, 0,
|
|
@@ -1155,7 +1186,8 @@ qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band,
|
|
|
|
|
|
while (payload_len >= sizeof(*tlv)) {
|
|
|
tlv_type = le16_to_cpu(tlv->type);
|
|
|
- tlv_len = le16_to_cpu(tlv->len) + sizeof(*tlv);
|
|
|
+ tlv_dlen = le16_to_cpu(tlv->len);
|
|
|
+ tlv_len = tlv_dlen + sizeof(*tlv);
|
|
|
|
|
|
if (tlv_len > payload_len) {
|
|
|
pr_warn("malformed TLV 0x%.2X; LEN: %zu\n",
|
|
@@ -1241,13 +1273,32 @@ qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band,
|
|
|
chan->hw_value, chan->flags, chan->max_power,
|
|
|
chan->max_reg_power);
|
|
|
break;
|
|
|
+ case WLAN_EID_HT_CAPABILITY:
|
|
|
+ if (unlikely(tlv_dlen !=
|
|
|
+ sizeof(struct ieee80211_ht_cap))) {
|
|
|
+ pr_err("bad HTCAP TLV len %zu\n", tlv_dlen);
|
|
|
+ goto error_ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ qtnf_cmd_resp_band_fill_htcap(tlv->val, &band->ht_cap);
|
|
|
+ break;
|
|
|
+ case WLAN_EID_VHT_CAPABILITY:
|
|
|
+ if (unlikely(tlv_dlen !=
|
|
|
+ sizeof(struct ieee80211_vht_cap))) {
|
|
|
+ pr_err("bad VHTCAP TLV len %zu\n", tlv_dlen);
|
|
|
+ goto error_ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ qtnf_cmd_resp_band_fill_vhtcap(tlv->val,
|
|
|
+ &band->vht_cap);
|
|
|
+ break;
|
|
|
default:
|
|
|
pr_warn("unknown TLV type: %#x\n", tlv_type);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
payload_len -= tlv_len;
|
|
|
- tlv = (struct qlink_tlv_hdr *)((u8 *)tlv + tlv_len);
|
|
|
+ tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_dlen);
|
|
|
}
|
|
|
|
|
|
if (payload_len) {
|
|
@@ -1469,13 +1520,13 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
|
|
|
- struct ieee80211_supported_band *band)
|
|
|
+int qtnf_cmd_band_info_get(struct qtnf_wmac *mac,
|
|
|
+ struct ieee80211_supported_band *band)
|
|
|
{
|
|
|
struct sk_buff *cmd_skb, *resp_skb = NULL;
|
|
|
size_t info_len;
|
|
|
- struct qlink_cmd_chans_info_get *cmd;
|
|
|
- struct qlink_resp_get_chan_info *resp;
|
|
|
+ struct qlink_cmd_band_info_get *cmd;
|
|
|
+ struct qlink_resp_band_info_get *resp;
|
|
|
u16 res_code = QLINK_CMD_RESULT_OK;
|
|
|
int ret = 0;
|
|
|
u8 qband;
|
|
@@ -1495,12 +1546,12 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
|
|
|
}
|
|
|
|
|
|
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0,
|
|
|
- QLINK_CMD_CHANS_INFO_GET,
|
|
|
+ QLINK_CMD_BAND_INFO_GET,
|
|
|
sizeof(*cmd));
|
|
|
if (!cmd_skb)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- cmd = (struct qlink_cmd_chans_info_get *)cmd_skb->data;
|
|
|
+ cmd = (struct qlink_cmd_band_info_get *)cmd_skb->data;
|
|
|
cmd->band = qband;
|
|
|
|
|
|
qtnf_bus_lock(mac->bus);
|
|
@@ -1517,7 +1568,7 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- resp = (struct qlink_resp_get_chan_info *)resp_skb->data;
|
|
|
+ resp = (struct qlink_resp_band_info_get *)resp_skb->data;
|
|
|
if (resp->band != qband) {
|
|
|
pr_err("MAC%u: reply band %u != cmd band %u\n", mac->macid,
|
|
|
resp->band, qband);
|
|
@@ -1525,7 +1576,7 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = qtnf_cmd_resp_fill_channels_info(band, resp, info_len);
|
|
|
+ ret = qtnf_cmd_resp_fill_band_info(band, resp, info_len);
|
|
|
|
|
|
out:
|
|
|
qtnf_bus_unlock(mac->bus);
|