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];

Reply via email to