summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/quantenna/qtnfmac/commands.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-01-31 14:31:10 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2018-01-31 14:31:10 -0800
commitb2fe5fa68642860e7de76167c3111623aa0d5de1 (patch)
treeb7f9b89b7039ecefbc35fe3c8e73a6ff972641dd /drivers/net/wireless/quantenna/qtnfmac/commands.c
parenta103950e0dd2058df5e8a8d4a915707bdcf205f0 (diff)
parenta54667f6728c2714a400f3c884727da74b6d1717 (diff)
downloadop-kernel-dev-b2fe5fa68642860e7de76167c3111623aa0d5de1.zip
op-kernel-dev-b2fe5fa68642860e7de76167c3111623aa0d5de1.tar.gz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: 1) Significantly shrink the core networking routing structures. Result of http://vger.kernel.org/~davem/seoul2017_netdev_keynote.pdf 2) Add netdevsim driver for testing various offloads, from Jakub Kicinski. 3) Support cross-chip FDB operations in DSA, from Vivien Didelot. 4) Add a 2nd listener hash table for TCP, similar to what was done for UDP. From Martin KaFai Lau. 5) Add eBPF based queue selection to tun, from Jason Wang. 6) Lockless qdisc support, from John Fastabend. 7) SCTP stream interleave support, from Xin Long. 8) Smoother TCP receive autotuning, from Eric Dumazet. 9) Lots of erspan tunneling enhancements, from William Tu. 10) Add true function call support to BPF, from Alexei Starovoitov. 11) Add explicit support for GRO HW offloading, from Michael Chan. 12) Support extack generation in more netlink subsystems. From Alexander Aring, Quentin Monnet, and Jakub Kicinski. 13) Add 1000BaseX, flow control, and EEE support to mvneta driver. From Russell King. 14) Add flow table abstraction to netfilter, from Pablo Neira Ayuso. 15) Many improvements and simplifications to the NFP driver bpf JIT, from Jakub Kicinski. 16) Support for ipv6 non-equal cost multipath routing, from Ido Schimmel. 17) Add resource abstration to devlink, from Arkadi Sharshevsky. 18) Packet scheduler classifier shared filter block support, from Jiri Pirko. 19) Avoid locking in act_csum, from Davide Caratti. 20) devinet_ioctl() simplifications from Al viro. 21) More TCP bpf improvements from Lawrence Brakmo. 22) Add support for onlink ipv6 route flag, similar to ipv4, from David Ahern. * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1925 commits) tls: Add support for encryption using async offload accelerator ip6mr: fix stale iterator net/sched: kconfig: Remove blank help texts openvswitch: meter: Use 64-bit arithmetic instead of 32-bit tcp_nv: fix potential integer overflow in tcpnv_acked r8169: fix RTL8168EP take too long to complete driver initialization. qmi_wwan: Add support for Quectel EP06 rtnetlink: enable IFLA_IF_NETNSID for RTM_NEWLINK ipmr: Fix ptrdiff_t print formatting ibmvnic: Wait for device response when changing MAC qlcnic: fix deadlock bug tcp: release sk_frag.page in tcp_disconnect ipv4: Get the address of interface correctly. net_sched: gen_estimator: fix lockdep splat net: macb: Handle HRESP error net/mlx5e: IPoIB, Fix copy-paste bug in flow steering refactoring ipv6: addrconf: break critical section in addrconf_verify_rtnl() ipv6: change route cache aging logic i40e/i40evf: Update DESC_NEEDED value to reflect larger value bnxt_en: cleanup DIM work on device shutdown ...
Diffstat (limited to 'drivers/net/wireless/quantenna/qtnfmac/commands.c')
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/commands.c581
1 files changed, 411 insertions, 170 deletions
diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c
index 8bc8dd6..deca006 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/commands.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c
@@ -162,6 +162,14 @@ static void qtnf_cmd_tlv_ie_set_add(struct sk_buff *cmd_skb, u8 frame_type,
memcpy(tlv->ie_data, buf, len);
}
+static inline size_t qtnf_cmd_acl_data_size(const struct cfg80211_acl_data *acl)
+{
+ size_t size = sizeof(struct qlink_acl_data) +
+ acl->n_acl_entries * sizeof(struct qlink_mac_address);
+
+ return size;
+}
+
static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
const struct cfg80211_ap_settings *s)
{
@@ -178,6 +186,10 @@ static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif,
if (cfg80211_chandef_valid(&s->chandef))
len += sizeof(struct qlink_tlv_chandef);
+ if (s->acl)
+ len += sizeof(struct qlink_tlv_hdr) +
+ qtnf_cmd_acl_data_size(s->acl);
+
if (len > (sizeof(struct qlink_cmd) + QTNF_MAX_CMD_BUF_SIZE)) {
pr_err("VIF%u.%u: can not fit AP settings: %u\n",
vif->mac->macid, vif->vifid, len);
@@ -203,7 +215,7 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_START_AP,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
cmd = (struct qlink_cmd_start_ap *)cmd_skb->data;
@@ -247,7 +259,7 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
chtlv->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANDEF);
chtlv->hdr.len = cpu_to_le16(sizeof(*chtlv) -
sizeof(chtlv->hdr));
- qlink_chandef_cfg2q(&s->chandef, &chtlv->chan);
+ qlink_chandef_cfg2q(&s->chandef, &chtlv->chdef);
}
qtnf_cmd_tlv_ie_set_add(cmd_skb, QLINK_IE_SET_BEACON_HEAD,
@@ -283,6 +295,16 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,
memcpy(tlv->val, s->vht_cap, sizeof(*s->vht_cap));
}
+ if (s->acl) {
+ size_t acl_size = qtnf_cmd_acl_data_size(s->acl);
+ struct qlink_tlv_hdr *tlv =
+ skb_put(cmd_skb, sizeof(*tlv) + acl_size);
+
+ tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA);
+ tlv->len = cpu_to_le16(acl_size);
+ qlink_acl_data_cfg2q(s->acl, (struct qlink_acl_data *)tlv->val);
+ }
+
qtnf_bus_lock(vif->mac->bus);
ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code);
@@ -313,7 +335,7 @@ int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_STOP_AP,
sizeof(struct qlink_cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -347,7 +369,7 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_REGISTER_MGMT,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -390,7 +412,7 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_SEND_MGMT_FRAME,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -436,7 +458,7 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_MGMT_SET_APPIE,
sizeof(struct qlink_cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len);
@@ -461,30 +483,8 @@ out:
}
static void
-qtnf_sta_info_parse_basic_counters(struct station_info *sinfo,
- const struct qlink_sta_stat_basic_counters *counters)
-{
- sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES) |
- BIT(NL80211_STA_INFO_TX_BYTES);
- sinfo->rx_bytes = get_unaligned_le64(&counters->rx_bytes);
- sinfo->tx_bytes = get_unaligned_le64(&counters->tx_bytes);
-
- sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS) |
- BIT(NL80211_STA_INFO_TX_PACKETS) |
- BIT(NL80211_STA_INFO_BEACON_RX);
- sinfo->rx_packets = get_unaligned_le32(&counters->rx_packets);
- sinfo->tx_packets = get_unaligned_le32(&counters->tx_packets);
- sinfo->rx_beacon = get_unaligned_le64(&counters->rx_beacons);
-
- sinfo->filled |= BIT(NL80211_STA_INFO_RX_DROP_MISC) |
- BIT(NL80211_STA_INFO_TX_FAILED);
- sinfo->rx_dropped_misc = get_unaligned_le32(&counters->rx_dropped);
- sinfo->tx_failed = get_unaligned_le32(&counters->tx_failed);
-}
-
-static void
qtnf_sta_info_parse_rate(struct rate_info *rate_dst,
- const struct qlink_sta_info_rate *rate_src)
+ const struct qlink_sta_info_rate *rate_src)
{
rate_dst->legacy = get_unaligned_le16(&rate_src->rate) * 10;
@@ -493,22 +493,23 @@ qtnf_sta_info_parse_rate(struct rate_info *rate_dst,
rate_dst->flags = 0;
switch (rate_src->bw) {
- case QLINK_STA_INFO_RATE_BW_5:
+ case QLINK_CHAN_WIDTH_5:
rate_dst->bw = RATE_INFO_BW_5;
break;
- case QLINK_STA_INFO_RATE_BW_10:
+ case QLINK_CHAN_WIDTH_10:
rate_dst->bw = RATE_INFO_BW_10;
break;
- case QLINK_STA_INFO_RATE_BW_20:
+ case QLINK_CHAN_WIDTH_20:
+ case QLINK_CHAN_WIDTH_20_NOHT:
rate_dst->bw = RATE_INFO_BW_20;
break;
- case QLINK_STA_INFO_RATE_BW_40:
+ case QLINK_CHAN_WIDTH_40:
rate_dst->bw = RATE_INFO_BW_40;
break;
- case QLINK_STA_INFO_RATE_BW_80:
+ case QLINK_CHAN_WIDTH_80:
rate_dst->bw = RATE_INFO_BW_80;
break;
- case QLINK_STA_INFO_RATE_BW_160:
+ case QLINK_CHAN_WIDTH_160:
rate_dst->bw = RATE_INFO_BW_160;
break;
default:
@@ -578,87 +579,125 @@ qtnf_sta_info_parse_flags(struct nl80211_sta_flag_update *dst,
}
static void
-qtnf_sta_info_parse_generic_info(struct station_info *sinfo,
- const struct qlink_sta_info_generic *info)
+qtnf_cmd_sta_info_parse(struct station_info *sinfo,
+ const struct qlink_tlv_hdr *tlv,
+ size_t resp_size)
{
- sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME) |
- BIT(NL80211_STA_INFO_INACTIVE_TIME);
- sinfo->connected_time = get_unaligned_le32(&info->connected_time);
- sinfo->inactive_time = get_unaligned_le32(&info->inactive_time);
+ const struct qlink_sta_stats *stats = NULL;
+ const u8 *map = NULL;
+ unsigned int map_len = 0;
+ unsigned int stats_len = 0;
+ u16 tlv_len;
+
+#define qtnf_sta_stat_avail(stat_name, bitn) \
+ (qtnf_utils_is_bit_set(map, bitn, map_len) && \
+ (offsetofend(struct qlink_sta_stats, stat_name) <= stats_len))
+
+ while (resp_size >= sizeof(*tlv)) {
+ tlv_len = le16_to_cpu(tlv->len);
+
+ switch (le16_to_cpu(tlv->type)) {
+ case QTN_TLV_ID_STA_STATS_MAP:
+ map_len = tlv_len;
+ map = tlv->val;
+ break;
+ case QTN_TLV_ID_STA_STATS:
+ stats_len = tlv_len;
+ stats = (const struct qlink_sta_stats *)tlv->val;
+ break;
+ default:
+ break;
+ }
- sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) |
- BIT(NL80211_STA_INFO_SIGNAL_AVG);
- sinfo->signal = info->rssi - 120;
- sinfo->signal_avg = info->rssi_avg - QLINK_RSSI_OFFSET;
+ resp_size -= tlv_len + sizeof(*tlv);
+ tlv = (const struct qlink_tlv_hdr *)(tlv->val + tlv_len);
+ }
- if (info->rx_rate.rate) {
+ if (!map || !stats)
+ return;
+
+ if (qtnf_sta_stat_avail(inactive_time, QLINK_STA_INFO_INACTIVE_TIME)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME);
+ sinfo->inactive_time = le32_to_cpu(stats->inactive_time);
+ }
+
+ if (qtnf_sta_stat_avail(connected_time,
+ QLINK_STA_INFO_CONNECTED_TIME)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
+ sinfo->connected_time = le32_to_cpu(stats->connected_time);
+ }
+
+ if (qtnf_sta_stat_avail(signal, QLINK_STA_INFO_SIGNAL)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+ sinfo->signal = stats->signal - QLINK_RSSI_OFFSET;
+ }
+
+ if (qtnf_sta_stat_avail(signal_avg, QLINK_STA_INFO_SIGNAL_AVG)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
+ sinfo->signal_avg = stats->signal_avg - QLINK_RSSI_OFFSET;
+ }
+
+ if (qtnf_sta_stat_avail(rxrate, QLINK_STA_INFO_RX_BITRATE)) {
sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
- qtnf_sta_info_parse_rate(&sinfo->rxrate, &info->rx_rate);
+ qtnf_sta_info_parse_rate(&sinfo->rxrate, &stats->rxrate);
}
- if (info->tx_rate.rate) {
+ if (qtnf_sta_stat_avail(txrate, QLINK_STA_INFO_TX_BITRATE)) {
sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
- qtnf_sta_info_parse_rate(&sinfo->txrate, &info->tx_rate);
+ qtnf_sta_info_parse_rate(&sinfo->txrate, &stats->txrate);
}
- sinfo->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
- qtnf_sta_info_parse_flags(&sinfo->sta_flags, &info->state);
-}
+ if (qtnf_sta_stat_avail(sta_flags, QLINK_STA_INFO_STA_FLAGS)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_STA_FLAGS);
+ qtnf_sta_info_parse_flags(&sinfo->sta_flags, &stats->sta_flags);
+ }
-static int qtnf_cmd_sta_info_parse(struct station_info *sinfo,
- const u8 *payload, size_t payload_size)
-{
- const struct qlink_sta_stat_basic_counters *counters;
- const struct qlink_sta_info_generic *sta_info;
- u16 tlv_type;
- u16 tlv_value_len;
- size_t tlv_full_len;
- const struct qlink_tlv_hdr *tlv;
+ if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES);
+ sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes);
+ }
- sinfo->filled = 0;
+ if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES);
+ sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes);
+ }
- tlv = (const struct qlink_tlv_hdr *)payload;
- while (payload_size >= sizeof(struct qlink_tlv_hdr)) {
- tlv_type = le16_to_cpu(tlv->type);
- tlv_value_len = le16_to_cpu(tlv->len);
- tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
- if (tlv_full_len > payload_size) {
- pr_warn("malformed TLV 0x%.2X; LEN: %u\n",
- tlv_type, tlv_value_len);
- return -EINVAL;
- }
- switch (tlv_type) {
- case QTN_TLV_ID_STA_BASIC_COUNTERS:
- if (unlikely(tlv_value_len < sizeof(*counters))) {
- pr_err("invalid TLV size %.4X: %u\n",
- tlv_type, tlv_value_len);
- break;
- }
+ if (qtnf_sta_stat_avail(rx_bytes, QLINK_STA_INFO_RX_BYTES64)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
+ sinfo->rx_bytes = le64_to_cpu(stats->rx_bytes);
+ }
- counters = (void *)tlv->val;
- qtnf_sta_info_parse_basic_counters(sinfo, counters);
- break;
- case QTN_TLV_ID_STA_GENERIC_INFO:
- if (unlikely(tlv_value_len < sizeof(*sta_info)))
- break;
+ if (qtnf_sta_stat_avail(tx_bytes, QLINK_STA_INFO_TX_BYTES64)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
+ sinfo->tx_bytes = le64_to_cpu(stats->tx_bytes);
+ }
- sta_info = (void *)tlv->val;
- qtnf_sta_info_parse_generic_info(sinfo, sta_info);
- break;
- default:
- pr_warn("unexpected TLV type: %.4X\n", tlv_type);
- break;
- }
- payload_size -= tlv_full_len;
- tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
+ if (qtnf_sta_stat_avail(rx_packets, QLINK_STA_INFO_RX_PACKETS)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
+ sinfo->rx_packets = le32_to_cpu(stats->rx_packets);
}
- if (payload_size) {
- pr_warn("malformed TLV buf; bytes left: %zu\n", payload_size);
- return -EINVAL;
+ if (qtnf_sta_stat_avail(tx_packets, QLINK_STA_INFO_TX_PACKETS)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
+ sinfo->tx_packets = le32_to_cpu(stats->tx_packets);
}
- return 0;
+ if (qtnf_sta_stat_avail(rx_beacon, QLINK_STA_INFO_BEACON_RX)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_BEACON_RX);
+ sinfo->rx_beacon = le64_to_cpu(stats->rx_beacon);
+ }
+
+ if (qtnf_sta_stat_avail(rx_dropped_misc, QLINK_STA_INFO_RX_DROP_MISC)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_DROP_MISC);
+ sinfo->rx_dropped_misc = le32_to_cpu(stats->rx_dropped_misc);
+ }
+
+ if (qtnf_sta_stat_avail(tx_failed, QLINK_STA_INFO_TX_FAILED)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
+ sinfo->tx_failed = le32_to_cpu(stats->tx_failed);
+ }
+
+#undef qtnf_sta_stat_avail
}
int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
@@ -674,8 +713,7 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_GET_STA_INFO,
sizeof(*cmd));
-
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -715,7 +753,9 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,
goto out;
}
- ret = qtnf_cmd_sta_info_parse(sinfo, resp->info, var_resp_len);
+ qtnf_cmd_sta_info_parse(sinfo,
+ (const struct qlink_tlv_hdr *)resp->info,
+ var_resp_len);
out:
qtnf_bus_unlock(vif->mac->bus);
@@ -738,7 +778,7 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
cmd_type,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -811,7 +851,7 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_DEL_INTF,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -908,6 +948,16 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
struct qtnf_hw_info *hwinfo = &bus->hw_info;
const struct qlink_tlv_hdr *tlv;
const struct qlink_tlv_reg_rule *tlv_rule;
+ const char *bld_name = NULL;
+ const char *bld_rev = NULL;
+ const char *bld_type = NULL;
+ const char *bld_label = NULL;
+ u32 bld_tmstamp = 0;
+ u32 plat_id = 0;
+ const char *hw_id = NULL;
+ const char *calibration_ver = NULL;
+ const char *uboot_ver = NULL;
+ u32 hw_ver = 0;
struct ieee80211_reg_rule *rule;
u16 tlv_type;
u16 tlv_value_len;
@@ -934,6 +984,10 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
hwinfo->rd->alpha2[0] = resp->alpha2[0];
hwinfo->rd->alpha2[1] = resp->alpha2[1];
+ bld_tmstamp = le32_to_cpu(resp->bld_tmstamp);
+ plat_id = le32_to_cpu(resp->plat_id);
+ hw_ver = le32_to_cpu(resp->hw_ver);
+
switch (resp->dfs_region) {
case QLINK_DFS_FCC:
hwinfo->rd->dfs_region = NL80211_DFS_FCC;
@@ -994,6 +1048,27 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
rule->flags = qtnf_cmd_resp_reg_rule_flags_parse(
le32_to_cpu(tlv_rule->flags));
break;
+ case QTN_TLV_ID_BUILD_NAME:
+ bld_name = (const void *)tlv->val;
+ break;
+ case QTN_TLV_ID_BUILD_REV:
+ bld_rev = (const void *)tlv->val;
+ break;
+ case QTN_TLV_ID_BUILD_TYPE:
+ bld_type = (const void *)tlv->val;
+ break;
+ case QTN_TLV_ID_BUILD_LABEL:
+ bld_label = (const void *)tlv->val;
+ break;
+ case QTN_TLV_ID_HW_ID:
+ hw_id = (const void *)tlv->val;
+ break;
+ case QTN_TLV_ID_CALIBRATION_VER:
+ calibration_ver = (const void *)tlv->val;
+ break;
+ case QTN_TLV_ID_UBOOT_VER:
+ uboot_ver = (const void *)tlv->val;
+ break;
default:
break;
}
@@ -1016,21 +1091,46 @@ qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus,
hwinfo->total_tx_chain, hwinfo->total_rx_chain,
hwinfo->hw_capab);
+ pr_info("\nBuild name: %s" \
+ "\nBuild revision: %s" \
+ "\nBuild type: %s" \
+ "\nBuild label: %s" \
+ "\nBuild timestamp: %lu" \
+ "\nPlatform ID: %lu" \
+ "\nHardware ID: %s" \
+ "\nCalibration version: %s" \
+ "\nU-Boot version: %s" \
+ "\nHardware version: 0x%08x",
+ bld_name, bld_rev, bld_type, bld_label,
+ (unsigned long)bld_tmstamp,
+ (unsigned long)plat_id,
+ hw_id, calibration_ver, uboot_ver, hw_ver);
+
+ strlcpy(hwinfo->fw_version, bld_label, sizeof(hwinfo->fw_version));
+ hwinfo->hw_version = hw_ver;
+
return 0;
}
static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
const u8 *tlv_buf, size_t tlv_buf_size)
{
- struct ieee80211_iface_limit *limits = NULL;
- const struct qlink_iface_limit *limit_record;
- size_t record_count = 0, rec = 0;
- u16 tlv_type, tlv_value_len;
- struct qlink_iface_comb_num *comb;
+ struct ieee80211_iface_combination *comb = NULL;
+ size_t n_comb = 0;
+ struct ieee80211_iface_limit *limits;
+ const struct qlink_iface_comb_num *comb_num;
+ const struct qlink_iface_limit_record *rec;
+ const struct qlink_iface_limit *lim;
+ u16 rec_len;
+ u16 tlv_type;
+ u16 tlv_value_len;
size_t tlv_full_len;
const struct qlink_tlv_hdr *tlv;
-
- mac->macinfo.n_limits = 0;
+ u8 *ext_capa = NULL;
+ u8 *ext_capa_mask = NULL;
+ u8 ext_capa_len = 0;
+ u8 ext_capa_mask_len = 0;
+ int i = 0;
tlv = (const struct qlink_tlv_hdr *)tlv_buf;
while (tlv_buf_size >= sizeof(struct qlink_tlv_hdr)) {
@@ -1045,52 +1145,89 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
switch (tlv_type) {
case QTN_TLV_ID_NUM_IFACE_COMB:
- if (unlikely(tlv_value_len != sizeof(*comb)))
+ if (tlv_value_len != sizeof(*comb_num))
return -EINVAL;
- comb = (void *)tlv->val;
- record_count = le16_to_cpu(comb->iface_comb_num);
+ comb_num = (void *)tlv->val;
+
+ /* free earlier iface comb memory */
+ qtnf_mac_iface_comb_free(mac);
- mac->macinfo.n_limits = record_count;
- /* free earlier iface limits memory */
- kfree(mac->macinfo.limits);
- mac->macinfo.limits =
- kzalloc(sizeof(*mac->macinfo.limits) *
- record_count, GFP_KERNEL);
+ mac->macinfo.n_if_comb =
+ le32_to_cpu(comb_num->iface_comb_num);
- if (unlikely(!mac->macinfo.limits))
+ mac->macinfo.if_comb =
+ kcalloc(mac->macinfo.n_if_comb,
+ sizeof(*mac->macinfo.if_comb),
+ GFP_KERNEL);
+
+ if (!mac->macinfo.if_comb)
return -ENOMEM;
- limits = mac->macinfo.limits;
+ comb = mac->macinfo.if_comb;
+
+ pr_debug("MAC%u: %zu iface combinations\n",
+ mac->macid, mac->macinfo.n_if_comb);
+
break;
case QTN_TLV_ID_IFACE_LIMIT:
- if (unlikely(!limits)) {
- pr_warn("MAC%u: limits are not inited\n",
+ if (unlikely(!comb)) {
+ pr_warn("MAC%u: no combinations advertised\n",
mac->macid);
return -EINVAL;
}
- if (unlikely(tlv_value_len != sizeof(*limit_record))) {
- pr_warn("MAC%u: record size mismatch\n",
+ if (n_comb >= mac->macinfo.n_if_comb) {
+ pr_warn("MAC%u: combinations count exceeded\n",
mac->macid);
- return -EINVAL;
+ n_comb++;
+ break;
}
- limit_record = (void *)tlv->val;
- limits[rec].max = le16_to_cpu(limit_record->max_num);
- limits[rec].types = qlink_iface_type_to_nl_mask(
- le16_to_cpu(limit_record->type));
+ rec = (void *)tlv->val;
+ rec_len = sizeof(*rec) + rec->n_limits * sizeof(*lim);
+
+ if (unlikely(tlv_value_len != rec_len)) {
+ pr_warn("MAC%u: record %zu size mismatch\n",
+ mac->macid, n_comb);
+ return -EINVAL;
+ }
- /* supported modes: STA, AP */
- limits[rec].types &= BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_AP_VLAN) |
- BIT(NL80211_IFTYPE_STATION);
+ limits = kzalloc(sizeof(*limits) * rec->n_limits,
+ GFP_KERNEL);
+ if (!limits)
+ return -ENOMEM;
- pr_debug("MAC%u: MAX: %u; TYPES: %.4X\n", mac->macid,
- limits[rec].max, limits[rec].types);
+ comb[n_comb].num_different_channels =
+ rec->num_different_channels;
+ comb[n_comb].max_interfaces =
+ le16_to_cpu(rec->max_interfaces);
+ comb[n_comb].n_limits = rec->n_limits;
+ comb[n_comb].limits = limits;
+
+ for (i = 0; i < rec->n_limits; i++) {
+ lim = &rec->limits[i];
+ limits[i].max = le16_to_cpu(lim->max_num);
+ limits[i].types =
+ qlink_iface_type_to_nl_mask(le16_to_cpu(lim->type));
+ pr_debug("MAC%u: comb[%zu]: MAX:%u TYPES:%.4X\n",
+ mac->macid, n_comb,
+ limits[i].max, limits[i].types);
+ }
- if (limits[rec].types)
- rec++;
+ n_comb++;
+ break;
+ case WLAN_EID_EXT_CAPABILITY:
+ if (unlikely(tlv_value_len > U8_MAX))
+ return -EINVAL;
+ ext_capa = (u8 *)tlv->val;
+ ext_capa_len = tlv_value_len;
+ break;
+ case QTN_TLV_ID_EXT_CAPABILITY_MASK:
+ if (unlikely(tlv_value_len > U8_MAX))
+ return -EINVAL;
+ ext_capa_mask = (u8 *)tlv->val;
+ ext_capa_mask_len = tlv_value_len;
break;
default:
break;
@@ -1106,12 +1243,40 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,
return -EINVAL;
}
- if (mac->macinfo.n_limits != rec) {
+ if (mac->macinfo.n_if_comb != n_comb) {
pr_err("MAC%u: combination mismatch: reported=%zu parsed=%zu\n",
- mac->macid, mac->macinfo.n_limits, rec);
+ mac->macid, mac->macinfo.n_if_comb, n_comb);
+ return -EINVAL;
+ }
+
+ if (ext_capa_len != ext_capa_mask_len) {
+ pr_err("MAC%u: ext_capa/_mask lengths mismatch: %u != %u\n",
+ mac->macid, ext_capa_len, ext_capa_mask_len);
return -EINVAL;
}
+ if (ext_capa_len > 0) {
+ ext_capa = kmemdup(ext_capa, ext_capa_len, GFP_KERNEL);
+ if (!ext_capa)
+ return -ENOMEM;
+
+ ext_capa_mask =
+ kmemdup(ext_capa_mask, ext_capa_mask_len, GFP_KERNEL);
+ if (!ext_capa_mask) {
+ kfree(ext_capa);
+ return -ENOMEM;
+ }
+ } else {
+ ext_capa = NULL;
+ ext_capa_mask = NULL;
+ }
+
+ kfree(mac->macinfo.extended_capabilities);
+ kfree(mac->macinfo.extended_capabilities_mask);
+ mac->macinfo.extended_capabilities = ext_capa;
+ mac->macinfo.extended_capabilities_mask = ext_capa_mask;
+ mac->macinfo.extended_capabilities_len = ext_capa_len;
+
return 0;
}
@@ -1143,6 +1308,7 @@ qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac,
mac_info->radar_detect_widths =
qlink_chan_width_mask_to_nl(le16_to_cpu(
resp_info->radar_detect_widths));
+ mac_info->max_acl_mac_addrs = le32_to_cpu(resp_info->max_acl_mac_addrs);
memcpy(&mac_info->ht_cap_mod_mask, &resp_info->ht_cap_mod_mask,
sizeof(mac_info->ht_cap_mod_mask));
@@ -1186,7 +1352,7 @@ qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
size_t tlv_len;
size_t tlv_dlen;
const struct qlink_tlv_hdr *tlv;
- const struct qlink_tlv_channel *qchan;
+ const struct qlink_channel *qchan;
struct ieee80211_channel *chan;
unsigned int chidx = 0;
u32 qflags;
@@ -1232,7 +1398,7 @@ qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
switch (tlv_type) {
case QTN_TLV_ID_CHANNEL:
- if (unlikely(tlv_len != sizeof(*qchan))) {
+ if (unlikely(tlv_dlen != sizeof(*qchan))) {
pr_err("invalid channel TLV len %zu\n",
tlv_len);
goto error_ret;
@@ -1243,7 +1409,7 @@ qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band,
goto error_ret;
}
- qchan = (const struct qlink_tlv_channel *)tlv;
+ qchan = (const struct qlink_channel *)tlv->val;
chan = &band->channels[chidx++];
qflags = le32_to_cpu(qchan->flags);
@@ -1490,7 +1656,7 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
QLINK_CMD_MAC_INFO,
sizeof(struct qlink_cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(mac->bus);
@@ -1528,7 +1694,7 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
QLINK_CMD_GET_HW_INFO,
sizeof(struct qlink_cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(bus);
@@ -1708,7 +1874,7 @@ int qtnf_cmd_send_init_fw(struct qtnf_bus *bus)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD,
QLINK_CMD_FW_INIT,
sizeof(struct qlink_cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(bus);
@@ -1757,7 +1923,7 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_ADD_KEY,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -1810,7 +1976,7 @@ int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_DEL_KEY,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -1851,7 +2017,7 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_SET_DEFAULT_KEY,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -1886,7 +2052,7 @@ int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_SET_DEFAULT_MGMT_KEY,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -1941,28 +2107,24 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_CHANGE_STA,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
cmd = (struct qlink_cmd_change_sta *)cmd_skb->data;
ether_addr_copy(cmd->sta_addr, mac);
+ cmd->flag_update.mask =
+ cpu_to_le32(qtnf_encode_sta_flags(params->sta_flags_mask));
+ cmd->flag_update.value =
+ cpu_to_le32(qtnf_encode_sta_flags(params->sta_flags_set));
switch (vif->wdev.iftype) {
case NL80211_IFTYPE_AP:
cmd->if_type = cpu_to_le16(QLINK_IFTYPE_AP);
- cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags(
- params->sta_flags_mask));
- cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags(
- params->sta_flags_set));
break;
case NL80211_IFTYPE_STATION:
cmd->if_type = cpu_to_le16(QLINK_IFTYPE_STATION);
- cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags(
- params->sta_flags_mask));
- cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags(
- params->sta_flags_set));
break;
default:
pr_err("unsupported iftype %d\n", vif->wdev.iftype);
@@ -1997,7 +2159,7 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_DEL_STA,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -2037,8 +2199,8 @@ static void qtnf_cmd_channel_tlv_add(struct sk_buff *cmd_skb,
qchan = skb_put_zero(cmd_skb, sizeof(*qchan));
qchan->hdr.type = cpu_to_le16(QTN_TLV_ID_CHANNEL);
qchan->hdr.len = cpu_to_le16(sizeof(*qchan) - sizeof(qchan->hdr));
- qchan->center_freq = cpu_to_le16(sc->center_freq);
- qchan->hw_value = cpu_to_le16(sc->hw_value);
+ qchan->chan.center_freq = cpu_to_le16(sc->center_freq);
+ qchan->chan.hw_value = cpu_to_le16(sc->hw_value);
if (sc->flags & IEEE80211_CHAN_NO_IR)
flags |= QLINK_CHAN_NO_IR;
@@ -2046,7 +2208,7 @@ static void qtnf_cmd_channel_tlv_add(struct sk_buff *cmd_skb,
if (sc->flags & IEEE80211_CHAN_RADAR)
flags |= QLINK_CHAN_RADAR;
- qchan->flags = cpu_to_le32(flags);
+ qchan->chan.flags = cpu_to_le32(flags);
}
int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
@@ -2067,7 +2229,7 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD,
QLINK_CMD_SCAN,
sizeof(struct qlink_cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(mac->bus);
@@ -2137,7 +2299,7 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_CONNECT,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
cmd = (struct qlink_cmd_connect *)cmd_skb->data;
@@ -2239,7 +2401,7 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_DISCONNECT,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(vif->mac->bus);
@@ -2273,7 +2435,7 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_UPDOWN_INTF,
sizeof(*cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
cmd = (struct qlink_cmd_updown *)cmd_skb->data;
@@ -2434,8 +2596,7 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,
cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid,
QLINK_CMD_CHAN_SWITCH,
sizeof(*cmd));
-
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(mac->bus);
@@ -2487,7 +2648,7 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)
cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
QLINK_CMD_CHAN_GET,
sizeof(struct qlink_cmd));
- if (unlikely(!cmd_skb))
+ if (!cmd_skb)
return -ENOMEM;
qtnf_bus_lock(bus);
@@ -2512,3 +2673,83 @@ out:
consume_skb(resp_skb);
return ret;
}
+
+int qtnf_cmd_start_cac(const struct qtnf_vif *vif,
+ const struct cfg80211_chan_def *chdef,
+ u32 cac_time_ms)
+{
+ struct qtnf_bus *bus = vif->mac->bus;
+ struct sk_buff *cmd_skb;
+ struct qlink_cmd_start_cac *cmd;
+ int ret;
+ u16 res_code;
+
+ cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
+ QLINK_CMD_START_CAC,
+ sizeof(*cmd));
+ if (!cmd_skb)
+ return -ENOMEM;
+
+ cmd = (struct qlink_cmd_start_cac *)cmd_skb->data;
+ cmd->cac_time_ms = cpu_to_le32(cac_time_ms);
+ qlink_chandef_cfg2q(chdef, &cmd->chan);
+
+ qtnf_bus_lock(bus);
+ ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
+ qtnf_bus_unlock(bus);
+
+ if (ret)
+ return ret;
+
+ switch (res_code) {
+ case QLINK_CMD_RESULT_OK:
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,
+ const struct cfg80211_acl_data *params)
+{
+ struct qtnf_bus *bus = vif->mac->bus;
+ struct sk_buff *cmd_skb;
+ struct qlink_tlv_hdr *tlv;
+ size_t acl_size = qtnf_cmd_acl_data_size(params);
+ u16 res_code;
+ int ret;
+
+ cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,
+ QLINK_CMD_SET_MAC_ACL,
+ sizeof(struct qlink_cmd));
+ if (!cmd_skb)
+ return -ENOMEM;
+
+ tlv = skb_put(cmd_skb, sizeof(*tlv) + acl_size);
+ tlv->type = cpu_to_le16(QTN_TLV_ID_ACL_DATA);
+ tlv->len = cpu_to_le16(acl_size);
+ qlink_acl_data_cfg2q(params, (struct qlink_acl_data *)tlv->val);
+
+ qtnf_bus_lock(bus);
+ ret = qtnf_cmd_send(bus, cmd_skb, &res_code);
+ qtnf_bus_unlock(bus);
+
+ if (unlikely(ret))
+ return ret;
+
+ switch (res_code) {
+ case QLINK_CMD_RESULT_OK:
+ break;
+ case QLINK_CMD_RESULT_INVALID:
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
OpenPOWER on IntegriCloud