Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f0dc59a authored by Arend van Spriel's avatar Arend van Spriel Committed by Kalle Valo
Browse files

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: default avatarHante Meuleman <meuleman@broadcom.com>
Reviewed-by: default avatarDaniel (Deognyoun) Kim <dekim@broadcom.com>
Reviewed-by: default avatarFranky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 2e5f66fe
Loading
Loading
Loading
Loading
+101 −73
Original line number Diff line number Diff line
@@ -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)) {
	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;
		}
	}
	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;
		if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
	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_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_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);
		}

		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);
			sinfo->txrate.legacy = le32_to_cpu(sta_info_le.tx_rate);
			sinfo->txrate.legacy /= 100;
		}
			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);
		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;
		}
			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);
		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);
		}
			sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
	}
	} else
		err = -EPERM;
done:
	brcmf_dbg(TRACE, "Exit\n");
	return err;
+60 −19
Original line number Diff line number Diff line
@@ -32,7 +32,11 @@
#define	BRCMF_BSS_INFO_VERSION	109 /* curr ver of brcmf_bss_info_le struct */
#define BRCMF_BSS_RSSI_ON_CHANNEL	0x0002

#define BRCMF_STA_ASSOC			0x10		/* Associated */
#define BRCMF_STA_WME              0x00000002      /* WMM association */
#define BRCMF_STA_AUTHE            0x00000008      /* Authenticated */
#define BRCMF_STA_ASSOC            0x00000010      /* Associated */
#define BRCMF_STA_AUTHO            0x00000020      /* Authorized */
#define BRCMF_STA_SCBSTATS         0x00004000      /* Per STA debug stats */

/* size of brcmf_scan_params not including variable length array */
#define BRCMF_SCAN_PARAMS_FIXED_SIZE	64
@@ -113,6 +117,7 @@
#define BRCMF_WOWL_MAXPATTERNSIZE	128

#define BRCMF_COUNTRY_BUF_SZ		4
#define BRCMF_ANT_MAX			4

/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
@@ -475,6 +480,42 @@ struct brcmf_sta_info_le {
	__le32 rx_rate;	/* Rate of last successful rx frame */
	__le32 rx_decrypt_succeeds;	/* # of packet decrypted successfully */
	__le32 rx_decrypt_failures;	/* # of packet decrypted failed */
	__le32 tx_tot_pkts;    /* # of tx pkts (ucast + mcast) */
	__le32 rx_tot_pkts;    /* # of data packets recvd (uni + mcast) */
	__le32 tx_mcast_pkts;  /* # of mcast pkts txed */
	__le64 tx_tot_bytes;   /* data bytes txed (ucast + mcast) */
	__le64 rx_tot_bytes;   /* data bytes recvd (ucast + mcast) */
	__le64 tx_ucast_bytes; /* data bytes txed (ucast) */
	__le64 tx_mcast_bytes; /* # data bytes txed (mcast) */
	__le64 rx_ucast_bytes; /* data bytes recvd (ucast) */
	__le64 rx_mcast_bytes; /* data bytes recvd (mcast) */
	s8 rssi[BRCMF_ANT_MAX];   /* per antenna rssi */
	s8 nf[BRCMF_ANT_MAX];     /* per antenna noise floor */
	__le16 aid;                    /* association ID */
	__le16 ht_capabilities;        /* advertised ht caps */
	__le16 vht_flags;              /* converted vht flags */
	__le32 tx_pkts_retry_cnt;      /* # of frames where a retry was
					 * exhausted.
					 */
	__le32 tx_pkts_retry_exhausted; /* # of user frames where a retry
					 * was exhausted
					 */
	s8 rx_lastpkt_rssi[BRCMF_ANT_MAX]; /* Per antenna RSSI of last
					    * received data frame.
					    */
	/* TX WLAN retry/failure statistics:
	 * Separated for host requested frames and locally generated frames.
	 * Include unicast frame only where the retries/failures can be counted.
	 */
	__le32 tx_pkts_total;          /* # user frames sent successfully */
	__le32 tx_pkts_retries;        /* # user frames retries */
	__le32 tx_pkts_fw_total;       /* # FW generated sent successfully */
	__le32 tx_pkts_fw_retries;     /* # retries for FW generated frames */
	__le32 tx_pkts_fw_retry_exhausted;     /* # FW generated where a retry
						* was exhausted
						*/
	__le32 rx_pkts_retried;        /* # rx with retry bit set */
	__le32 tx_rate_fallback;       /* lowest fallback TX rate */
};

struct brcmf_chanspec_list {