On Tue, Jan 15, 2019 at 10:01:42PM +0100, Stefan Sperling wrote:
> This diff makes 'ifconfig bwfm0' display whether 11n is active or not,
> what the current Tx rate is, and show up-to-date RSSI measurements.
> I'm leaving display of 11ac Tx rates for future work because that will
> require a change in struct ieet80211_node.
> 
> Tested with 'bwfm0 at pci1 dev 0 function 0 "Broadcom BCM4350" rev 0x08: msi'
> as a client with 11a and 11n APs, and in hostap mode with an iwn(4) client.
> 
> I had a bwfm(4) USB device as well somewhere, but can't find it :-/
> 
> 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    15 Jan 2019 20:39:22 -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,136 @@ bwfm_watchdog(struct ifnet *ifp)
>       ieee80211_watchdog(ifp);
>  }
>  
> +extern struct ifmedia_baudrate ifmedia_baudrate_descriptions[];
> +
> +/*
> + * This function might lie because some MCS have equivalent baudrates.
> + * However, this is the best we can do given that the firmware only
> + * reports Tx baudrates.
> + */
> +uint64_t
> +bwfm_rate2mword(uint64_t baudrate)
> +{
> +     int i;
> +     uint64_t mword;
> +
> +     for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
> +             mword = ifmedia_baudrate_descriptions[i].ifmb_word;
> +             if (!IFM_TYPE_MATCH(IFM_IEEE80211, mword))
> +                     continue;
> +             if (ifmedia_baudrate_descriptions[i].ifmb_baudrate == baudrate)
> +                     return mword;
> +     }
> +
> +     /* Not known. */
> +     return 0;
> +}
> +
> +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;
> +     uint64_t mword;
> +     int 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);
> +     if (txrate == 0xffffffff) /* Seen this happening during association. */
> +             return;
> +
> +     mword = bwfm_rate2mword(txrate * 1000);
> +     if ((sta.flags & BWFM_STA_N_CAP) &&
> +         IFM_SUBTYPE(mword) >= IFM_IEEE80211_HT_MCS0) {
> +             /* 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);
> +
> +             if ((sta.flags & BWFM_STA_VHT_CAP) &&
> +                 IFM_SUBTYPE(mword) >= IFM_IEEE80211_VHT_MCS0) {
> +                     /* TODO: Can't store VHT MCS in ni yet... */
> +             } else
> +                     ni->ni_txmcs = ieee80211_media2mcs(mword);
> +     } 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 / 2 >= txrate / 1000) {
> +                                     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;
> +     case IEEE80211_M_HOSTAP:
> +             ieee80211_iterate_nodes(ic, bwfm_update_node, sc);
> +             break;

I think HOSTAP needs

#ifndef IEEE80211_STA_ONLY

otherwise ramdisk kernels don't compile.

With that fixed, ok patrick@. :)

> +     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 +696,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