diff options
author | Arend van Spriel <arend@broadcom.com> | 2015-06-11 00:12:19 +0200 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-06-15 12:55:21 +0300 |
commit | 1f0dc59a6de93586fcfc04696a61946408ffc56a (patch) | |
tree | e6b333b9cf680e6ad4c9340e562a932afc81898f /drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | |
parent | 2e5f66fe95936b5e723da6d0b5813bc638a32520 (diff) |
brcmfmac: rework .get_station() callback
The .get_station() cfg80211 callback is used in several scenarios. In
managed mode it can obtain information about the access-point and its
BSS parameters. In managed mode it can also obtain information about
TDLS peers. In AP mode it can obtain information about connected
clients.
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 174 |
1 files changed, 101 insertions, 73 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index a668a351b0c5..6e45b400ce4b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -2396,27 +2396,80 @@ brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp) brcmf_err("set wsec error (%d)\n", err); } +static void brcmf_convert_sta_flags(u32 fw_sta_flags, struct station_info *si) +{ + struct nl80211_sta_flag_update *sfu; + + brcmf_dbg(TRACE, "flags %08x\n", fw_sta_flags); + si->filled |= BIT(NL80211_STA_INFO_STA_FLAGS); + sfu = &si->sta_flags; + sfu->mask = BIT(NL80211_STA_FLAG_WME) | + BIT(NL80211_STA_FLAG_AUTHENTICATED) | + BIT(NL80211_STA_FLAG_ASSOCIATED) | + BIT(NL80211_STA_FLAG_AUTHORIZED); + if (fw_sta_flags & BRCMF_STA_WME) + sfu->set |= BIT(NL80211_STA_FLAG_WME); + if (fw_sta_flags & BRCMF_STA_AUTHE) + sfu->set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); + if (fw_sta_flags & BRCMF_STA_ASSOC) + sfu->set |= BIT(NL80211_STA_FLAG_ASSOCIATED); + if (fw_sta_flags & BRCMF_STA_AUTHO) + sfu->set |= BIT(NL80211_STA_FLAG_AUTHORIZED); +} + +static void brcmf_fill_bss_param(struct brcmf_if *ifp, struct station_info *si) +{ + struct { + __le32 len; + struct brcmf_bss_info_le bss_le; + } *buf; + u16 capability; + int err; + + buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (!buf) + return; + + buf->len = cpu_to_le32(WL_BSS_INFO_MAX); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, buf, + WL_BSS_INFO_MAX); + if (err) { + brcmf_err("Failed to get bss info (%d)\n", err); + return; + } + si->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); + si->bss_param.beacon_interval = le16_to_cpu(buf->bss_le.beacon_period); + si->bss_param.dtim_period = buf->bss_le.dtim_period; + capability = le16_to_cpu(buf->bss_le.capability); + if (capability & IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT) + si->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; + if (capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; + if (capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) + si->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; +} + static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; - struct brcmf_scb_val_le scb_val; - int rssi; - s32 rate; s32 err = 0; - u8 *bssid = profile->bssid; struct brcmf_sta_info_le sta_info_le; - u32 beacon_period; - u32 dtim_period; + u32 sta_flags; + u32 is_tdls_peer; brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac); if (!check_vif_up(ifp->vif)) return -EIO; - if (brcmf_is_apmode(ifp->vif)) { - memcpy(&sta_info_le, mac, ETH_ALEN); + memset(&sta_info_le, 0, sizeof(sta_info_le)); + memcpy(&sta_info_le, mac, ETH_ALEN); + err = brcmf_fil_iovar_data_get(ifp, "tdls_sta_info", + &sta_info_le, + sizeof(sta_info_le)); + is_tdls_peer = !err; + if (err) { err = brcmf_fil_iovar_data_get(ifp, "sta_info", &sta_info_le, sizeof(sta_info_le)); @@ -2424,73 +2477,48 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, brcmf_err("GET STA INFO failed, %d\n", err); goto done; } - sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME); - sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000; - if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) { - sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME); - sinfo->connected_time = le32_to_cpu(sta_info_le.in); - } - brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n", - sinfo->inactive_time, sinfo->connected_time); - } else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) { - if (memcmp(mac, bssid, ETH_ALEN)) { - brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n", - mac, bssid); - err = -ENOENT; - goto done; - } - /* Report the current tx rate */ - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); - if (err) { - brcmf_err("Could not get rate (%d)\n", err); - goto done; - } else { + } + brcmf_dbg(TRACE, "version %d\n", le16_to_cpu(sta_info_le.ver)); + sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000; + sta_flags = le32_to_cpu(sta_info_le.flags); + brcmf_convert_sta_flags(sta_flags, sinfo); + sinfo->sta_flags.mask |= BIT(NL80211_STA_FLAG_TDLS_PEER); + if (is_tdls_peer) + sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); + else + sinfo->sta_flags.set &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); + if (sta_flags & BRCMF_STA_ASSOC) { + sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME); + sinfo->connected_time = le32_to_cpu(sta_info_le.in); + brcmf_fill_bss_param(ifp, sinfo); + } + if (sta_flags & BRCMF_STA_SCBSTATS) { + sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->tx_failed = le32_to_cpu(sta_info_le.tx_failures); + sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); + sinfo->tx_packets = le32_to_cpu(sta_info_le.tx_pkts); + sinfo->tx_packets += le32_to_cpu(sta_info_le.tx_mcast_pkts); + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); + sinfo->rx_packets = le32_to_cpu(sta_info_le.rx_ucast_pkts); + sinfo->rx_packets += le32_to_cpu(sta_info_le.rx_mcast_pkts); + if (sinfo->tx_packets) { sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); - sinfo->txrate.legacy = rate * 5; - brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2); + sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate); + sinfo->txrate.legacy /= 100; } - - if (test_bit(BRCMF_VIF_STATUS_CONNECTED, - &ifp->vif->sme_state)) { - memset(&scb_val, 0, sizeof(scb_val)); - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, - &scb_val, sizeof(scb_val)); - if (err) { - brcmf_err("Could not get rssi (%d)\n", err); - goto done; - } else { - rssi = le32_to_cpu(scb_val.val); - sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); - sinfo->signal = rssi; - brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); - } - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD, - &beacon_period); - if (err) { - brcmf_err("Could not get beacon period (%d)\n", - err); - goto done; - } else { - sinfo->bss_param.beacon_interval = - beacon_period; - brcmf_dbg(CONN, "Beacon peroid %d\n", - beacon_period); - } - err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD, - &dtim_period); - if (err) { - brcmf_err("Could not get DTIM period (%d)\n", - err); - goto done; - } else { - sinfo->bss_param.dtim_period = dtim_period; - brcmf_dbg(CONN, "DTIM peroid %d\n", - dtim_period); - } - sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM); + if (sinfo->rx_packets) { + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE); + sinfo->rxrate.legacy = le32_to_cpu(sta_info_le.rx_rate); + sinfo->rxrate.legacy /= 100; } - } else - err = -EPERM; + if (le16_to_cpu(sta_info_le.ver) >= 4) { + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES); + sinfo->tx_bytes = le64_to_cpu(sta_info_le.tx_tot_bytes); + sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES); + sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes); + } + } done: brcmf_dbg(TRACE, "Exit\n"); return err; |