On Mon, Jan 21, 2019 at 10:54:24AM +0100, Stefan Sperling wrote:
> Before committing this, I'd like to address the problem that this diff
> cannot work for 11n rates which aren't mentioned in if_media.h. Rates using
> SGI and those with a 40MHz channel can't be listed there because if_media.h
> baudrate defintions only support a single key/value number pairing.
> The same issue will need to be solved for 11ac rates.
>
> I'm considering adding complete MCS index tables for 11n and 11ac to net80211,
> right below our definitions of standard 11a/b/g rate sets.
Updated diff which makes use of net80211 11n rate tables added last week
instead of using ifmedia definitions.
Our 11n tables are not yet complete. In cases where a Tx rate can't yet
be found in 11n rate tables, ifconfig will display "MCS-0" for now.
Ok?
Index: bwfm.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/bwfm.c,v
retrieving revision 1.54
diff -u -p -r1.54 bwfm.c
--- bwfm.c 25 Jul 2018 20:37:11 -0000 1.54
+++ bwfm.c 29 Jan 2019 14:30:28 -0000
@@ -59,6 +59,8 @@ void bwfm_start(struct ifnet *);
void bwfm_init(struct ifnet *);
void bwfm_stop(struct ifnet *);
void bwfm_watchdog(struct ifnet *);
+void bwfm_update_node(void *, struct ieee80211_node *);
+void bwfm_update_nodes(struct bwfm_softc *);
int bwfm_ioctl(struct ifnet *, u_long, caddr_t);
int bwfm_media_change(struct ifnet *);
@@ -549,10 +551,138 @@ bwfm_watchdog(struct ifnet *ifp)
ieee80211_watchdog(ifp);
}
+/*
+ * Tx-rate to MCS conversion might lie since some rates map to multiple MCS.
+ * But this is the best we can do given that firmware only reports kbit/s.
+ */
+
+int
+bwfm_rate2vhtmcs(uint32_t txrate)
+{
+ /* TODO */
+ return -1;
+}
+
+int
+bwfm_rate2htmcs(uint32_t txrate)
+{
+ int i, j;
+ const struct ieee80211_ht_rateset *rs;
+
+ for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) {
+ rs = &ieee80211_std_ratesets_11n[i];
+ for (j = 0; j < rs->nrates; j++) {
+ if (rs->rates[j] == txrate / 500)
+ return rs->min_mcs + j;
+ }
+ }
+
+ return -1;
+}
+
+void
+bwfm_update_node(void *arg, struct ieee80211_node *ni)
+{
+ struct bwfm_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct bwfm_sta_info sta;
+ uint32_t flags;
+ int8_t rssi;
+ uint32_t txrate;
+ int mcs, i;
+
+ memset(&sta, 0, sizeof(sta));
+ memcpy((uint8_t *)&sta, ni->ni_macaddr, sizeof(ni->ni_macaddr));
+
+ if (bwfm_fwvar_var_get_data(sc, "sta_info", &sta, sizeof(sta)))
+ return;
+
+ if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, sta.ea))
+ return;
+
+ if (le16toh(sta.ver) < 4)
+ return;
+
+ flags = le32toh(sta.flags);
+ if ((flags & BWFM_STA_SCBSTATS) == 0)
+ return;
+
+ rssi = 0;
+ for (i = 0; i < BWFM_ANT_MAX; i++) {
+ if (sta.rssi[i] >= 0)
+ continue;
+ if (rssi == 0 || sta.rssi[i] > rssi)
+ rssi = sta.rssi[i];
+ }
+ if (rssi)
+ ni->ni_rssi = rssi;
+
+ txrate = le32toh(sta.tx_rate); /* in kbit/s */
+ if (txrate == 0xffffffff) /* Seen this happening during association. */
+ return;
+
+ if ((le32toh(sta.flags) & BWFM_STA_VHT_CAP) &&
+ (mcs = bwfm_rate2vhtmcs(txrate)) >= 0) {
+ /* TODO: Can't store VHT MCS in ni yet... */
+ } else if ((le32toh(sta.flags) & BWFM_STA_N_CAP) &&
+ (mcs = bwfm_rate2htmcs(txrate)) >= 0) {
+ /* Tell net80211 that firmware has negotiated 11n. */
+ ni->ni_flags |= IEEE80211_NODE_HT;
+ if (ic->ic_curmode < IEEE80211_MODE_11N)
+ ieee80211_setmode(ic, IEEE80211_MODE_11N);
+ ni->ni_txmcs = mcs;
+ } else {
+ /*
+ * In 11n mode a fallback to legacy rates is transparent
+ * to net80211. Just pretend we were using MCS 0.
+ */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ ni->ni_txmcs = 0;
+ } else {
+ /* We're in 11a/g mode. Map to a legacy rate. */
+ for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
+ uint8_t rate = ni->ni_rates.rs_rates[i];
+ rate &= IEEE80211_RATE_VAL;
+ if (rate == txrate / 500) {
+ ni->ni_txrate = i;
+ break;
+ }
+ }
+ }
+ }
+}
+
+void
+bwfm_update_nodes(struct bwfm_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni;
+
+ switch (ic->ic_opmode) {
+ case IEEE80211_M_STA:
+ bwfm_update_node(sc, ic->ic_bss);
+ /* Update cached copy in the nodes tree as well. */
+ ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr);
+ if (ni) {
+ ni->ni_rssi = ic->ic_bss->ni_rssi;
+ }
+ break;
+#ifndef IEEE80211_STA_ONLY
+ case IEEE80211_M_HOSTAP:
+ ieee80211_iterate_nodes(ic, bwfm_update_node, sc);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
int
bwfm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
int s, error = 0;
+ struct bwfm_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
s = splnet();
switch (cmd) {
@@ -568,6 +698,12 @@ bwfm_ioctl(struct ifnet *ifp, u_long cmd
bwfm_stop(ifp);
}
break;
+ case SIOCGIFMEDIA:
+ case SIOCG80211NODE:
+ case SIOCG80211ALLNODES:
+ if (ic->ic_state == IEEE80211_S_RUN)
+ bwfm_update_nodes(sc);
+ /* fall through */
default:
error = ieee80211_ioctl(ifp, cmd, data);
}
Index: bwfmreg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/bwfmreg.h,v
retrieving revision 1.16
diff -u -p -r1.16 bwfmreg.h
--- bwfmreg.h 7 Feb 2018 21:44:09 -0000 1.16
+++ bwfmreg.h 15 Jan 2019 18:42:33 -0000
@@ -370,6 +370,137 @@ struct bwfm_bss_info {
uint16_t snr;
};
+#define BWFM_MAXRATES_IN_SET BWFM_MCSSET_LEN
+#define BWFM_ANT_MAX 4
+#define BWFM_VHT_CAP_MCS_MAP_NSS_MAX 8
+#define BWFM_HE_CAP_MCS_MAP_NSS_MAX BWFM_VHT_CAP_MCS_MAP_NSS_MAX
+
+struct bwfm_sta_rateset_v5 {
+ uint32_t count;
+ /* rates in 500kbps units w/hi bit set if basic */
+ uint8_t rates[BWFM_MAXRATES_IN_SET];
+ uint8_t mcs[BWFM_MCSSET_LEN];
+ uint16_t vht_mcs[BWFM_VHT_CAP_MCS_MAP_NSS_MAX];
+};
+
+struct bwfm_sta_rateset_v7 {
+ uint16_t version;
+ uint16_t len;
+ uint32_t count;
+ /* rates in 500kbps units w/hi bit set if basic */
+ uint8_t rates[BWFM_MAXRATES_IN_SET];
+ uint8_t mcs[BWFM_MCSSET_LEN];
+ uint16_t vht_mcs[BWFM_VHT_CAP_MCS_MAP_NSS_MAX];
+ uint16_t he_mcs[BWFM_HE_CAP_MCS_MAP_NSS_MAX];
+};
+
+struct bwfm_sta_info {
+ uint16_t ver;
+ uint16_t len;
+ uint16_t cap; /* sta's advertised capabilities */
+
+ uint32_t flags;
+#define BWFM_STA_BRCM 0x00000001 /* Running a Broadcom driver */
+#define BWFM_STA_WME 0x00000002 /* WMM association */
+#define BWFM_STA_NONERP 0x00000004 /* No ERP */
+#define BWFM_STA_AUTHE 0x00000008 /* Authenticated */
+#define BWFM_STA_ASSOC 0x00000010 /* Associated */
+#define BWFM_STA_AUTHO 0x00000020 /* Authorized */
+#define BWFM_STA_WDS 0x00000040 /* Wireless Distribution System */
+#define BWFM_STA_WDS_LINKUP 0x00000080 /* WDS traffic/probes flowing */
+#define BWFM_STA_PS 0x00000100 /* STA in power save mode, says AP */
+#define BWFM_STA_APSD_BE 0x00000200 /* APSD for AC_BE default enabled */
+#define BWFM_STA_APSD_BK 0x00000400 /* APSD for AC_BK default enabled */
+#define BWFM_STA_APSD_VI 0x00000800 /* APSD for AC_VI default enabled */
+#define BWFM_STA_APSD_VO 0x00001000 /* APSD for AC_VO default enabled */
+#define BWFM_STA_N_CAP 0x00002000 /* STA 802.11n capable */
+#define BWFM_STA_SCBSTATS 0x00004000 /* Per STA debug stats */
+#define BWFM_STA_AMPDU_CAP 0x00008000 /* STA AMPDU capable */
+#define BWFM_STA_AMSDU_CAP 0x00010000 /* STA AMSDU capable */
+#define BWFM_STA_MIMO_PS 0x00020000 /* mimo ps mode is enabled */
+#define BWFM_STA_MIMO_RTS 0x00040000 /* send rts in mimo ps mode */
+#define BWFM_STA_RIFS_CAP 0x00080000 /* rifs enabled */
+#define BWFM_STA_VHT_CAP 0x00100000 /* STA VHT(11ac) capable */
+#define BWFM_STA_WPS 0x00200000 /* WPS state */
+#define BWFM_STA_DWDS_CAP 0x01000000 /* DWDS CAP */
+#define BWFM_STA_DWDS 0x02000000 /* DWDS active */
+
+ uint32_t idle; /* time since data pkt rx'd from sta */
+ uint8_t ea[ETHER_ADDR_LEN];
+ uint32_t count; /* # rates in this set */
+ uint8_t rates[BWFM_MAXRATES_IN_SET]; /* rates in 500kbps units */
+ /* w/hi bit set if basic */
+ uint32_t in; /* seconds elapsed since associated */
+ uint32_t listen_interval_inms; /* Min Listen interval in ms for STA */
+
+ /* Fields valid for ver >= 3 */
+ uint32_t tx_pkts; /* # of packets transmitted */
+ uint32_t tx_failures; /* # of packets failed */
+ uint32_t rx_ucast_pkts; /* # of unicast packets received */
+ uint32_t rx_mcast_pkts; /* # of multicast packets received */
+ uint32_t tx_rate; /* Rate of last successful tx frame, in bps */
+ uint32_t rx_rate; /* Rate of last successful rx frame, in bps */
+ uint32_t rx_decrypt_succeeds; /* # of packet decrypted successfully */
+ uint32_t rx_decrypt_failures; /* # of packet decrypted failed */
+
+ /* Fields valid for ver >= 4 */
+ uint32_t tx_tot_pkts; /* # of tx pkts (ucast + mcast) */
+ uint32_t rx_tot_pkts; /* # of data packets recvd (uni + mcast) */
+ uint32_t tx_mcast_pkts; /* # of mcast pkts txed */
+ uint64_t tx_tot_bytes; /* data bytes txed (ucast + mcast) */
+ uint64_t rx_tot_bytes; /* data bytes recvd (ucast + mcast) */
+ uint64_t tx_ucast_bytes; /* data bytes txed (ucast) */
+ uint64_t tx_mcast_bytes; /* # data bytes txed (mcast) */
+ uint64_t rx_ucast_bytes; /* data bytes recvd (ucast) */
+ uint64_t rx_mcast_bytes; /* data bytes recvd (mcast) */
+ int8_t rssi[BWFM_ANT_MAX]; /* per antenna rssi */
+ int8_t nf[BWFM_ANT_MAX]; /* per antenna noise floor */
+ uint16_t aid; /* association ID */
+ uint16_t ht_capabilities; /* advertised ht caps */
+ uint16_t vht_flags; /* converted vht flags */
+ uint32_t tx_pkts_retry_cnt; /* # of frames where a retry was
+ * exhausted.
+ */
+ uint32_t tx_pkts_retry_exhausted; /* # of user frames where a retry
+ * was exhausted
+ */
+ int8_t rx_lastpkt_rssi[BWFM_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.
+ */
+ uint32_t tx_pkts_total; /* # user frames sent successfully */
+ uint32_t tx_pkts_retries; /* # user frames retries */
+ uint32_t tx_pkts_fw_total; /* # FW generated sent successfully */
+ uint32_t tx_pkts_fw_retries; /* # retries for FW generated frames */
+ uint32_t tx_pkts_fw_retry_exhausted; /* # FW generated where a retry
+ * was exhausted
+ */
+ uint32_t rx_pkts_retried; /* # rx with retry bit set */
+ uint32_t tx_rate_fallback; /* lowest fallback TX rate */
+
+ union {
+ struct {
+ struct bwfm_sta_rateset_v5 rateset_adv;
+ } v5;
+
+ struct {
+ uint32_t rx_dur_total; /* user RX duration (estimate) */
+ uint16_t chanspec;
+ uint16_t pad_1;
+ struct bwfm_sta_rateset_v7 rateset_adv;
+ uint16_t wpauth; /* authentication type */
+ uint8_t algo; /* crypto alogorithm */
+ uint8_t pad_2;
+ uint32_t tx_rspec;/* Rate of last successful tx frame */
+ uint32_t rx_rspec;/* Rate of last successful rx frame */
+ uint32_t wnm_cap;
+ } v7;
+ };
+};
+
struct bwfm_ssid {
uint32_t len;
uint8_t ssid[BWFM_MAX_SSID_LEN];