prima: Add new vendor command to get link properties
Add support in driver for a new vendor command to get
the link properties nss, rate flags and operating
frequency.
Change-Id: Ie3b8d5b2c3886055d303441c5d8b2f2a0a2719bd
CRs-Fixed: 899952
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index af362c1..bb44804 100644
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -326,6 +326,8 @@
// Save dot11mode in which STA associated to AP
pHddStaCtx->conn_info.dot11Mode = pRoamInfo->u.pConnectedProfile->dot11Mode;
+
+ pHddStaCtx->conn_info.rate_flags = pRoamInfo->maxRateFlags;
}
}
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index ab96977..412c940 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -6997,6 +6997,175 @@
}
#endif
+static const struct
+nla_policy
+qca_wlan_vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_MAX+1] = {
+ [QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = { .type = NLA_UNSPEC },
+};
+
+/**
+ * wlan_hdd_cfg80211_get_link_properties() - This function is used to
+ * get link properties like nss, rate flags and operating frequency for
+ * the connection with the given peer.
+ * @wiphy: WIPHY structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of the data received
+ *
+ * This function return the above link properties on success.
+ *
+ * Return: 0 on success and errno on failure
+ */
+static int wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data,
+ int data_len)
+{
+ hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+ struct net_device *dev = wdev->netdev;
+ hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_station_ctx_t *hdd_sta_ctx;
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX+1];
+ uint8_t peer_mac[VOS_MAC_ADDR_SIZE];
+ uint32_t sta_id;
+ struct sk_buff *reply_skb;
+ uint32_t rate_flags = 0;
+ uint8_t nss;
+ uint8_t final_rate_flags = 0;
+ uint32_t freq;
+ v_CONTEXT_t pVosContext = NULL;
+ ptSapContext pSapCtx = NULL;
+
+ if (0 != wlan_hdd_validate_context(hdd_ctx)) {
+ hddLog(VOS_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
+ return -EINVAL;
+ }
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len,
+ qca_wlan_vendor_attr_policy)) {
+ hddLog(VOS_TRACE_LEVEL_ERROR, FL("Invalid attribute"));
+ return -EINVAL;
+ }
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("Attribute peerMac not provided for mode=%d"),
+ adapter->device_mode);
+ return -EINVAL;
+ }
+
+ memcpy(peer_mac, nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]),
+ sizeof(peer_mac));
+ hddLog(VOS_TRACE_LEVEL_INFO,
+ FL("peerMac="MAC_ADDRESS_STR" for device_mode:%d"),
+ MAC_ADDR_ARRAY(peer_mac), adapter->device_mode);
+
+ if (adapter->device_mode == WLAN_HDD_INFRA_STATION ||
+ adapter->device_mode == WLAN_HDD_P2P_CLIENT) {
+ hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+ if ((hdd_sta_ctx->conn_info.connState !=
+ eConnectionState_Associated) ||
+ !vos_mem_compare(hdd_sta_ctx->conn_info.bssId, peer_mac,
+ VOS_MAC_ADDRESS_LEN)) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("Not Associated to mac "MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(peer_mac));
+ return -EINVAL;
+ }
+
+ nss = 1; //pronto supports only one spatial stream
+ freq = vos_chan_to_freq(
+ hdd_sta_ctx->conn_info.operationChannel);
+ rate_flags = hdd_sta_ctx->conn_info.rate_flags;
+
+ } else if (adapter->device_mode == WLAN_HDD_P2P_GO ||
+ adapter->device_mode == WLAN_HDD_SOFTAP) {
+
+ pVosContext = ( WLAN_HDD_GET_CTX(adapter))->pvosContext;
+ pSapCtx = VOS_GET_SAP_CB(pVosContext);
+ if(pSapCtx == NULL){
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ FL("psapCtx is NULL"));
+ return -ENOENT;
+ }
+
+
+ for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) {
+ if (pSapCtx->aStaInfo[sta_id].isUsed &&
+ !vos_is_macaddr_broadcast(
+ &pSapCtx->aStaInfo[sta_id].macAddrSTA) &&
+ vos_mem_compare(
+ &pSapCtx->aStaInfo[sta_id].macAddrSTA,
+ peer_mac, VOS_MAC_ADDRESS_LEN))
+ break;
+ }
+
+ if (WLAN_MAX_STA_COUNT == sta_id) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("No active peer with mac="MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(peer_mac));
+ return -EINVAL;
+ }
+
+ nss = 1; //pronto supports only one spatial stream
+ freq = vos_chan_to_freq(
+ (WLAN_HDD_GET_AP_CTX_PTR(adapter))->operatingChannel);
+ rate_flags = pSapCtx->aStaInfo[sta_id].rate_flags;
+ } else {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("Not Associated! with mac"MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(peer_mac));
+ return -EINVAL;
+ }
+
+ if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
+ if (rate_flags & eHAL_TX_RATE_VHT80) {
+ final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
+ final_rate_flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+ } else if (rate_flags & eHAL_TX_RATE_VHT40) {
+ final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
+ final_rate_flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ } else if (rate_flags & eHAL_TX_RATE_VHT20) {
+ final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
+ } else if (rate_flags & (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
+ final_rate_flags |= RATE_INFO_FLAGS_MCS;
+ if (rate_flags & eHAL_TX_RATE_HT40)
+ final_rate_flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ }
+
+ if (rate_flags & eHAL_TX_RATE_SGI) {
+ if (!(final_rate_flags & RATE_INFO_FLAGS_VHT_MCS))
+ final_rate_flags |= RATE_INFO_FLAGS_MCS;
+ final_rate_flags |= RATE_INFO_FLAGS_SHORT_GI;
+ }
+ }
+
+ reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+ sizeof(u8) + sizeof(u8) + sizeof(u32) + NLMSG_HDRLEN);
+
+ if (NULL == reply_skb) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("getLinkProperties: skb alloc failed"));
+ return -EINVAL;
+ }
+
+ if (nla_put_u8(reply_skb,
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS,
+ nss) ||
+ nla_put_u8(reply_skb,
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS,
+ final_rate_flags) ||
+ nla_put_u32(reply_skb,
+ QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ,
+ freq)) {
+ hddLog(VOS_TRACE_LEVEL_ERROR, FL("nla_put failed"));
+ kfree_skb(reply_skb);
+ return -EINVAL;
+ }
+
+ return cfg80211_vendor_cmd_reply(reply_skb);
+}
+
const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
{
{
@@ -7225,8 +7394,16 @@
WIPHY_VENDOR_CMD_NEED_NETDEV |
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = wlan_hdd_cfg80211_offloaded_packets
- }
+ },
#endif
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_NETDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wlan_hdd_cfg80211_get_link_properties
+ }
};
/* vendor specific events */
diff --git a/CORE/HDD/src/wlan_hdd_hostapd.c b/CORE/HDD/src/wlan_hdd_hostapd.c
index 77e6f5f..9cf9f5d 100644
--- a/CORE/HDD/src/wlan_hdd_hostapd.c
+++ b/CORE/HDD/src/wlan_hdd_hostapd.c
@@ -1020,6 +1020,15 @@
vos_status, MAC_ADDR_ARRAY(wrqu.addr.sa_data));
}
+ staId =
+ pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staId;
+ if (VOS_IS_STATUS_SUCCESS(vos_status))
+ {
+
+ pSapCtx->aStaInfo[staId].rate_flags =
+ pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.rate_flags;
+ }
+
// Stop AP inactivity timer
if (pHddApCtx->hdd_ap_inactivity_timer.state == VOS_TIMER_STATE_RUNNING)
{