|
@@ -4960,32 +4960,384 @@ static inline int32_t remote_station_put_u64(struct sk_buff *skb,
|
|
|
#endif
|
|
|
|
|
|
/**
|
|
|
- * hdd_get_station_remote() - get remote peer's info
|
|
|
+ * hdd_add_survey_info_sap_get_len - get data length used in
|
|
|
+ * hdd_add_survey_info_sap()
|
|
|
+ *
|
|
|
+ * This function calculates the data length used in hdd_add_survey_info_sap()
|
|
|
+ *
|
|
|
+ * Return: total data length used in hdd_add_survey_info_sap()
|
|
|
+ */
|
|
|
+static uint32_t hdd_add_survey_info_sap_get_len(void)
|
|
|
+{
|
|
|
+ return ((NLA_HDRLEN) + (sizeof(uint32_t) + NLA_HDRLEN));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_survey_info - add survey info attribute
|
|
|
+ * @skb: pointer to response skb buffer
|
|
|
+ * @stainfo: station information
|
|
|
+ * @idx: attribute type index for nla_next_start()
|
|
|
+ *
|
|
|
+ * This function adds survey info attribute to response skb buffer
|
|
|
+ *
|
|
|
+ * Return : 0 on success and errno on failure
|
|
|
+ */
|
|
|
+static int32_t hdd_add_survey_info_sap(struct sk_buff *skb,
|
|
|
+ struct hdd_station_info *stainfo,
|
|
|
+ int idx)
|
|
|
+{
|
|
|
+ struct nlattr *nla_attr;
|
|
|
+
|
|
|
+ nla_attr = nla_nest_start(skb, idx);
|
|
|
+ if (!nla_attr)
|
|
|
+ goto fail;
|
|
|
+ if (nla_put_u32(skb, NL80211_SURVEY_INFO_FREQUENCY,
|
|
|
+ stainfo->freq)) {
|
|
|
+ hdd_err("put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ nla_nest_end(skb, nla_attr);
|
|
|
+ return 0;
|
|
|
+fail:
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_tx_bitrate_sap_get_len - get data length used in
|
|
|
+ * hdd_add_tx_bitrate_sap()
|
|
|
+ *
|
|
|
+ * This function calculates the data length used in hdd_add_tx_bitrate_sap()
|
|
|
+ *
|
|
|
+ * Return: total data length used in hdd_add_tx_bitrate_sap()
|
|
|
+ */
|
|
|
+static uint32_t hdd_add_tx_bitrate_sap_get_len(void)
|
|
|
+{
|
|
|
+ return ((NLA_HDRLEN) + (sizeof(uint8_t) + NLA_HDRLEN));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_tx_bitrate_sap - add vhs nss info attribute
|
|
|
+ * @skb: pointer to response skb buffer
|
|
|
+ * @stainfo: station information
|
|
|
+ * @idx: attribute type index for nla_next_start()
|
|
|
+ *
|
|
|
+ * This function adds vht nss attribute to response skb buffer
|
|
|
+ *
|
|
|
+ * Return : 0 on success and errno on failure
|
|
|
+ */
|
|
|
+static int hdd_add_tx_bitrate_sap(struct sk_buff *skb,
|
|
|
+ struct hdd_station_info *stainfo,
|
|
|
+ int idx)
|
|
|
+{
|
|
|
+ struct nlattr *nla_attr;
|
|
|
+
|
|
|
+ nla_attr = nla_nest_start(skb, idx);
|
|
|
+ if (!nla_attr)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ if (nla_put_u8(skb, NL80211_RATE_INFO_VHT_NSS,
|
|
|
+ stainfo->nss)) {
|
|
|
+ hdd_err("put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ nla_nest_end(skb, nla_attr);
|
|
|
+ return 0;
|
|
|
+fail:
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_sta_info_sap_get_len - get data length used in
|
|
|
+ * hdd_add_sta_info_sap()
|
|
|
+ *
|
|
|
+ * This function calculates the data length used in hdd_add_sta_info_sap()
|
|
|
+ *
|
|
|
+ * Return: total data length used in hdd_add_sta_info_sap()
|
|
|
+ */
|
|
|
+static uint32_t hdd_add_sta_info_sap_get_len(void)
|
|
|
+{
|
|
|
+ return ((NLA_HDRLEN) + (sizeof(uint8_t) + NLA_HDRLEN) +
|
|
|
+ hdd_add_tx_bitrate_sap_get_len());
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_sta_info_sap - add sta signal info attribute
|
|
|
+ * @skb: pointer to response skb buffer
|
|
|
+ * @stainfo: station information
|
|
|
+ * @idx: attribute type index for nla_next_start()
|
|
|
+ *
|
|
|
+ * This function adds sta signal attribute to response skb buffer
|
|
|
+ *
|
|
|
+ * Return : 0 on success and errno on failure
|
|
|
+ */
|
|
|
+static int32_t hdd_add_sta_info_sap(struct sk_buff *skb, int8_t rssi,
|
|
|
+ struct hdd_station_info *stainfo, int idx)
|
|
|
+{
|
|
|
+ struct nlattr *nla_attr;
|
|
|
+
|
|
|
+ nla_attr = nla_nest_start(skb, idx);
|
|
|
+ if (!nla_attr)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ if (nla_put_u8(skb, NL80211_STA_INFO_SIGNAL, rssi)) {
|
|
|
+ hdd_err("put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ if (hdd_add_tx_bitrate_sap(skb, stainfo, NL80211_STA_INFO_TX_BITRATE))
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ nla_nest_end(skb, nla_attr);
|
|
|
+ return 0;
|
|
|
+fail:
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_link_standard_info_sap_get_len - get data length used in
|
|
|
+ * hdd_add_link_standard_info_sap()
|
|
|
+ *
|
|
|
+ * This function calculates the data length used in
|
|
|
+ * hdd_add_link_standard_info_sap()
|
|
|
+ *
|
|
|
+ * Return: total data length used in hdd_add_link_standard_info_sap()
|
|
|
+ */
|
|
|
+static uint32_t hdd_add_link_standard_info_sap_get_len(void)
|
|
|
+{
|
|
|
+ return ((NLA_HDRLEN) +
|
|
|
+ hdd_add_survey_info_sap_get_len() +
|
|
|
+ hdd_add_sta_info_sap_get_len() +
|
|
|
+ (sizeof(uint32_t) + NLA_HDRLEN));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_link_standard_info_sap - add add link info attribut
|
|
|
+ * @skb: pointer to response skb buffer
|
|
|
+ * @stainfo: station information
|
|
|
+ * @idx: attribute type index for nla_next_start()
|
|
|
+ *
|
|
|
+ * This function adds link info attribut to response skb buffer
|
|
|
+ *
|
|
|
+ * Return : 0 on success and errno on failure
|
|
|
+ */
|
|
|
+static int hdd_add_link_standard_info_sap(struct sk_buff *skb, int8_t rssi,
|
|
|
+ struct hdd_station_info *stainfo,
|
|
|
+ int idx)
|
|
|
+{
|
|
|
+ struct nlattr *nla_attr;
|
|
|
+
|
|
|
+ nla_attr = nla_nest_start(skb, idx);
|
|
|
+ if (!nla_attr)
|
|
|
+ goto fail;
|
|
|
+ if (hdd_add_survey_info_sap(skb, stainfo, NL80211_ATTR_SURVEY_INFO))
|
|
|
+ goto fail;
|
|
|
+ if (hdd_add_sta_info_sap(skb, rssi, stainfo, NL80211_ATTR_STA_INFO))
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ if (nla_put_u32(skb, NL80211_ATTR_REASON_CODE, stainfo->reason_code)) {
|
|
|
+ hdd_err("Reason code put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ nla_nest_end(skb, nla_attr);
|
|
|
+ return 0;
|
|
|
+fail:
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_ap_standard_info_sap_get_len - get data length used in
|
|
|
+ * hdd_add_ap_standard_info_sap()
|
|
|
+ * @stainfo: station information
|
|
|
+ *
|
|
|
+ * This function calculates the data length used in
|
|
|
+ * hdd_add_ap_standard_info_sap()
|
|
|
+ *
|
|
|
+ * Return: total data length used in hdd_add_ap_standard_info_sap()
|
|
|
+ */
|
|
|
+static uint32_t hdd_add_ap_standard_info_sap_get_len(
|
|
|
+ struct hdd_station_info *stainfo)
|
|
|
+{
|
|
|
+ uint32_t len;
|
|
|
+
|
|
|
+ len = NLA_HDRLEN;
|
|
|
+ if (stainfo->vht_present)
|
|
|
+ len += (sizeof(stainfo->vht_caps) + NLA_HDRLEN);
|
|
|
+ if (stainfo->ht_present)
|
|
|
+ len += (sizeof(stainfo->ht_caps) + NLA_HDRLEN);
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_add_ap_standard_info_sap - add HT and VHT info attributes
|
|
|
+ * @skb: pointer to response skb buffer
|
|
|
+ * @stainfo: station information
|
|
|
+ * @idx: attribute type index for nla_next_start()
|
|
|
+ *
|
|
|
+ * This function adds HT and VHT info attributes to response skb buffer
|
|
|
+ *
|
|
|
+ * Return : 0 on success and errno on failure
|
|
|
+ */
|
|
|
+static int hdd_add_ap_standard_info_sap(struct sk_buff *skb,
|
|
|
+ struct hdd_station_info *stainfo,
|
|
|
+ int idx)
|
|
|
+{
|
|
|
+ struct nlattr *nla_attr;
|
|
|
+
|
|
|
+ nla_attr = nla_nest_start(skb, idx);
|
|
|
+ if (!nla_attr)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ if (stainfo->vht_present) {
|
|
|
+ if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY,
|
|
|
+ sizeof(stainfo->vht_caps),
|
|
|
+ &stainfo->vht_caps)) {
|
|
|
+ hdd_err("put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (stainfo->ht_present) {
|
|
|
+ if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY,
|
|
|
+ sizeof(stainfo->ht_caps),
|
|
|
+ &stainfo->ht_caps)) {
|
|
|
+ hdd_err("put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ nla_nest_end(skb, nla_attr);
|
|
|
+ return 0;
|
|
|
+fail:
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_decode_ch_width - decode channel band width based
|
|
|
+ * @ch_width: encoded enum value holding channel band width
|
|
|
+ *
|
|
|
+ * This function decodes channel band width from the given encoded enum value.
|
|
|
+ *
|
|
|
+ * Returns: decoded channel band width.
|
|
|
+ */
|
|
|
+static uint8_t hdd_decode_ch_width(tSirMacHTChannelWidth ch_width)
|
|
|
+{
|
|
|
+ switch (ch_width) {
|
|
|
+ case 0:
|
|
|
+ return 20;
|
|
|
+ case 1:
|
|
|
+ return 40;
|
|
|
+ case 2:
|
|
|
+ return 80;
|
|
|
+ case 3:
|
|
|
+ case 4:
|
|
|
+ return 160;
|
|
|
+ default:
|
|
|
+ hdd_debug("invalid enum: %d", ch_width);
|
|
|
+ return 20;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_get_cached_station_remote() - get cached(deleted) peer's info
|
|
|
* @hdd_ctx: hdd context
|
|
|
* @adapter: hostapd interface
|
|
|
* @mac_addr: mac address of requested peer
|
|
|
*
|
|
|
- * This function collect and indicate the remote peer's info
|
|
|
+ * This function collect and indicate the cached(deleted) peer's info
|
|
|
*
|
|
|
* Return: 0 on success, otherwise error value
|
|
|
*/
|
|
|
-static int hdd_get_station_remote(struct hdd_context *hdd_ctx,
|
|
|
- struct hdd_adapter *adapter,
|
|
|
- struct qdf_mac_addr mac_addr)
|
|
|
+
|
|
|
+static int hdd_get_cached_station_remote(struct hdd_context *hdd_ctx,
|
|
|
+ struct hdd_adapter *adapter,
|
|
|
+ struct qdf_mac_addr mac_addr)
|
|
|
{
|
|
|
- struct hdd_station_info *stainfo = hdd_get_stainfo(adapter->sta_info,
|
|
|
- mac_addr);
|
|
|
+ struct hdd_station_info *stainfo = hdd_get_stainfo(
|
|
|
+ adapter->cache_sta_info,
|
|
|
+ mac_addr);
|
|
|
struct sk_buff *skb = NULL;
|
|
|
- struct sir_peer_info_ext peer_info;
|
|
|
- uint32_t nl_buf_len;
|
|
|
- bool txrx_rate = true;
|
|
|
+ uint32_t nl_buf_len = NLMSG_HDRLEN;
|
|
|
+ uint8_t channel_width;
|
|
|
|
|
|
if (!stainfo) {
|
|
|
hdd_err("peer " MAC_ADDRESS_STR " not found",
|
|
|
MAC_ADDR_ARRAY(mac_addr.bytes));
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ nl_buf_len += hdd_add_link_standard_info_sap_get_len() +
|
|
|
+ hdd_add_ap_standard_info_sap_get_len(stainfo) +
|
|
|
+ (sizeof(stainfo->mode) + NLA_HDRLEN) +
|
|
|
+ (sizeof(stainfo->ch_width) + NLA_HDRLEN) +
|
|
|
+ (sizeof(stainfo->tx_rate) + NLA_HDRLEN) +
|
|
|
+ (sizeof(stainfo->rx_rate) + NLA_HDRLEN);
|
|
|
+
|
|
|
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
|
|
|
+ if (!skb) {
|
|
|
+ hdd_err(FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hdd_add_link_standard_info_sap(skb, stainfo->rssi, stainfo,
|
|
|
+ LINK_INFO_STANDARD_NL80211_ATTR)) {
|
|
|
+ hdd_err("link standard put fail");
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
+ if (hdd_add_ap_standard_info_sap(skb, stainfo,
|
|
|
+ AP_INFO_STANDARD_NL80211_ATTR)) {
|
|
|
+ hdd_err("ap standard put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* upper layer expects decoded channel BW */
|
|
|
+ channel_width = hdd_decode_ch_width(stainfo->ch_width);
|
|
|
+
|
|
|
+ if (nla_put_u32(skb, REMOTE_SUPPORTED_MODE,
|
|
|
+ hdd_convert_dot11mode(
|
|
|
+ stainfo->mode)) ||
|
|
|
+ nla_put_u8(skb, REMOTE_CH_WIDTH, channel_width)) {
|
|
|
+ hdd_err("remote ch put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ if (nla_put_u32(skb, REMOTE_LAST_TX_RATE, stainfo->tx_rate)) {
|
|
|
+ hdd_err("tx rate put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ if (nla_put_u32(skb, REMOTE_LAST_RX_RATE, stainfo->rx_rate)) {
|
|
|
+ hdd_err("rx rate put fail");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ qdf_mem_zero(stainfo, sizeof(*stainfo));
|
|
|
+
|
|
|
+ return cfg80211_vendor_cmd_reply(skb);
|
|
|
+fail:
|
|
|
+ if (skb)
|
|
|
+ kfree_skb(skb);
|
|
|
+
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * hdd_get_cached_station_remote() - get connected peer's info
|
|
|
+ * @hdd_ctx: hdd context
|
|
|
+ * @adapter: hostapd interface
|
|
|
+ * @mac_addr: mac address of requested peer
|
|
|
+ *
|
|
|
+ * This function collect and indicate the connected peer's info
|
|
|
+ *
|
|
|
+ * Return: 0 on success, otherwise error value
|
|
|
+ */
|
|
|
+static int hdd_get_connected_station_info(struct hdd_context *hdd_ctx,
|
|
|
+ struct hdd_adapter *adapter,
|
|
|
+ struct qdf_mac_addr mac_addr,
|
|
|
+ struct hdd_station_info *stainfo)
|
|
|
+{
|
|
|
+ struct sk_buff *skb = NULL;
|
|
|
+ uint32_t nl_buf_len;
|
|
|
+ struct sir_peer_info_ext peer_info;
|
|
|
+ bool txrx_rate = true;
|
|
|
+
|
|
|
nl_buf_len = NLMSG_HDRLEN;
|
|
|
nl_buf_len += (sizeof(stainfo->max_phy_rate) + NLA_HDRLEN) +
|
|
|
(sizeof(stainfo->tx_packets) + NLA_HDRLEN) +
|
|
@@ -5082,6 +5434,43 @@ fail:
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * hdd_get_station_remote() - get remote peer's info
|
|
|
+ * @hdd_ctx: hdd context
|
|
|
+ * @adapter: hostapd interface
|
|
|
+ * @mac_addr: mac address of requested peer
|
|
|
+ *
|
|
|
+ * This function collect and indicate the remote peer's info
|
|
|
+ *
|
|
|
+ * Return: 0 on success, otherwise error value
|
|
|
+ */
|
|
|
+static int hdd_get_station_remote(struct hdd_context *hdd_ctx,
|
|
|
+ struct hdd_adapter *adapter,
|
|
|
+ struct qdf_mac_addr mac_addr)
|
|
|
+{
|
|
|
+ struct hdd_station_info *stainfo = hdd_get_stainfo(adapter->sta_info,
|
|
|
+ mac_addr);
|
|
|
+ int status = 0;
|
|
|
+ bool is_associated = false;
|
|
|
+
|
|
|
+ if (!stainfo) {
|
|
|
+ status = hdd_get_cached_station_remote(hdd_ctx, adapter,
|
|
|
+ mac_addr);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ is_associated = hdd_is_peer_associated(adapter, &mac_addr);
|
|
|
+ if (!is_associated) {
|
|
|
+ status = hdd_get_cached_station_remote(hdd_ctx, adapter,
|
|
|
+ mac_addr);
|
|
|
+ return status;
|
|
|
+ }
|
|
|
+
|
|
|
+ status = hdd_get_connected_station_info(hdd_ctx, adapter,
|
|
|
+ mac_addr, stainfo);
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* __hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd
|
|
|
* @wiphy: corestack handler
|