Add initial support for MIMO statistics to net80211.
This introduces struct ieee80211_rx_stats - which stores the various kinds of RX statistics which a MIMO and non-MIMO 802.11 device can export. It also fleshes out the mimo export to userland (node_getmimoinfo()). It assumes that MIMO radios (for now) export both ctl and ext channels. Non-11n MIMO radios are possible (and I believe Atheros made at least one), so if that chipset support is added, extra flags to the struct ieee80211_rx_stats can be added to extend this support. Two new input functions have been added - ieee80211_input_mimo() and ieee80211_input_mimo_all() - which MIMO-aware devices can call with MIMO specific statistics. 802.11 devices calling the non-MIMO input functions will still function.
This commit is contained in:
parent
7ab2ab919c
commit
864ab11425
@ -387,10 +387,16 @@ struct ieee80211_regdomain {
|
||||
/*
|
||||
* MIMO antenna/radio state.
|
||||
*/
|
||||
|
||||
#define IEEE80211_MAX_CHAINS 3
|
||||
#define IEEE80211_MAX_EVM_PILOTS 6
|
||||
|
||||
/*
|
||||
* XXX This doesn't yet export both ctl/ext chain details
|
||||
*/
|
||||
struct ieee80211_mimo_info {
|
||||
int8_t rssi[3]; /* per-antenna rssi */
|
||||
int8_t noise[3]; /* per-antenna noise floor */
|
||||
uint8_t pad[2];
|
||||
int8_t rssi[IEEE80211_MAX_CHAINS]; /* per-antenna rssi */
|
||||
int8_t noise[IEEE80211_MAX_CHAINS]; /* per-antenna noise floor */
|
||||
uint32_t evm[3]; /* EVM data */
|
||||
};
|
||||
#endif /* _NET80211__IEEE80211_H_ */
|
||||
|
@ -57,8 +57,53 @@ __FBSDID("$FreeBSD$");
|
||||
#include <net/ethernet.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
ieee80211_process_mimo(struct ieee80211_node *ni, struct ieee80211_rx_stats *rx)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Verify the required MIMO bits are set */
|
||||
if ((rx->r_flags & (IEEE80211_R_C_CHAIN | IEEE80211_R_C_NF | IEEE80211_R_C_RSSI)) !=
|
||||
(IEEE80211_R_C_CHAIN | IEEE80211_R_C_NF | IEEE80211_R_C_RSSI))
|
||||
return;
|
||||
|
||||
/* XXX This assumes the MIMO radios have both ctl and ext chains */
|
||||
for (i = 0; i < MIN(rx->c_chain, IEEE80211_MAX_CHAINS); i++) {
|
||||
IEEE80211_RSSI_LPF(ni->ni_mimo_rssi_ctl[i], rx->c_rssi_ctl[i]);
|
||||
IEEE80211_RSSI_LPF(ni->ni_mimo_rssi_ext[i], rx->c_rssi_ext[i]);
|
||||
}
|
||||
|
||||
/* XXX This also assumes the MIMO radios have both ctl and ext chains */
|
||||
for(i = 0; i < MIN(rx->c_chain, IEEE80211_MAX_CHAINS); i++) {
|
||||
ni->ni_mimo_noise_ctl[i] = rx->c_nf_ctl[i];
|
||||
ni->ni_mimo_noise_ext[i] = rx->c_nf_ext[i];
|
||||
}
|
||||
ni->ni_mimo_chains = rx->c_chain;
|
||||
}
|
||||
|
||||
int
|
||||
ieee80211_input_mimo(struct ieee80211_node *ni, struct mbuf *m,
|
||||
struct ieee80211_rx_stats *rx)
|
||||
{
|
||||
/* XXX should assert IEEE80211_R_NF and IEEE80211_R_RSSI are set */
|
||||
ieee80211_process_mimo(ni, rx);
|
||||
return ieee80211_input(ni, m, rx->rssi, rx->nf);
|
||||
}
|
||||
|
||||
int
|
||||
ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf)
|
||||
{
|
||||
struct ieee80211_rx_stats rx;
|
||||
|
||||
rx.r_flags = IEEE80211_R_NF | IEEE80211_R_RSSI;
|
||||
rx.nf = nf;
|
||||
rx.rssi = rssi;
|
||||
return ieee80211_input_mimo_all(ic, m, &rx);
|
||||
}
|
||||
|
||||
int
|
||||
ieee80211_input_mimo_all(struct ieee80211com *ic, struct mbuf *m,
|
||||
struct ieee80211_rx_stats *rx)
|
||||
{
|
||||
struct ieee80211vap *vap;
|
||||
int type = -1;
|
||||
@ -96,7 +141,7 @@ ieee80211_input_all(struct ieee80211com *ic, struct mbuf *m, int rssi, int nf)
|
||||
m = NULL;
|
||||
}
|
||||
ni = ieee80211_ref_node(vap->iv_bss);
|
||||
type = ieee80211_input(ni, mcopy, rssi, nf);
|
||||
type = ieee80211_input_mimo(ni, mcopy, rx);
|
||||
ieee80211_free_node(ni);
|
||||
}
|
||||
if (m != NULL) /* no vaps, reclaim mbuf */
|
||||
|
@ -1085,7 +1085,26 @@ static void
|
||||
node_getmimoinfo(const struct ieee80211_node *ni,
|
||||
struct ieee80211_mimo_info *info)
|
||||
{
|
||||
/* XXX zero data? */
|
||||
int i;
|
||||
uint32_t avgrssi;
|
||||
int32_t rssi;
|
||||
|
||||
bzero(info, sizeof(*info));
|
||||
|
||||
for (i = 0; i < ni->ni_mimo_chains; i++) {
|
||||
avgrssi = ni->ni_mimo_rssi_ctl[i];
|
||||
if (avgrssi == IEEE80211_RSSI_DUMMY_MARKER) {
|
||||
info->rssi[i] = 0;
|
||||
} else {
|
||||
rssi = IEEE80211_RSSI_GET(avgrssi);
|
||||
info->rssi[i] = rssi < 0 ? 0 : rssi > 127 ? 127 : rssi;
|
||||
}
|
||||
info->noise[i] = ni->ni_mimo_noise_ctl[i];
|
||||
}
|
||||
|
||||
/* XXX ext radios? */
|
||||
|
||||
/* XXX EVM? */
|
||||
}
|
||||
|
||||
struct ieee80211_node *
|
||||
|
@ -166,6 +166,13 @@ struct ieee80211_node {
|
||||
uint32_t ni_avgrssi; /* recv ssi state */
|
||||
int8_t ni_noise; /* noise floor */
|
||||
|
||||
/* mimo statistics */
|
||||
uint32_t ni_mimo_rssi_ctl[IEEE80211_MAX_CHAINS];
|
||||
uint32_t ni_mimo_rssi_ext[IEEE80211_MAX_CHAINS];
|
||||
uint8_t ni_mimo_noise_ctl[IEEE80211_MAX_CHAINS];
|
||||
uint8_t ni_mimo_noise_ext[IEEE80211_MAX_CHAINS];
|
||||
uint8_t ni_mimo_chains;
|
||||
|
||||
/* header */
|
||||
uint8_t ni_macaddr[IEEE80211_ADDR_LEN];
|
||||
uint8_t ni_bssid[IEEE80211_ADDR_LEN];
|
||||
|
@ -61,9 +61,36 @@ void ieee80211_syncflag(struct ieee80211vap *, int flag);
|
||||
void ieee80211_syncflag_ht(struct ieee80211vap *, int flag);
|
||||
void ieee80211_syncflag_ext(struct ieee80211vap *, int flag);
|
||||
|
||||
#define IEEE80211_R_NF 0x0000001 /* global NF value valid */
|
||||
#define IEEE80211_R_RSSI 0x0000002 /* global RSSI value valid */
|
||||
#define IEEE80211_R_C_CHAIN 0x0000004 /* RX chain count valid */
|
||||
#define IEEE80211_R_C_NF 0x0000008 /* per-chain NF value valid */
|
||||
#define IEEE80211_R_C_RSSI 0x0000010 /* per-chain RSSI value valid */
|
||||
#define IEEE80211_R_C_EVM 0x0000020 /* per-chain EVM valid */
|
||||
#define IEEE80211_R_C_HT40 0x0000040 /* RX'ed packet is 40mhz, pilots 4,5 valid */
|
||||
|
||||
struct ieee80211_rx_stats {
|
||||
uint32_t r_flags; /* IEEE80211_R_* flags */
|
||||
uint8_t c_chain; /* number of RX chains involved */
|
||||
int16_t c_nf_ctl[IEEE80211_MAX_CHAINS]; /* per-chain NF */
|
||||
int16_t c_nf_ext[IEEE80211_MAX_CHAINS]; /* per-chain NF */
|
||||
int16_t c_rssi_ctl[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */
|
||||
int16_t c_rssi_ext[IEEE80211_MAX_CHAINS]; /* per-chain RSSI */
|
||||
uint8_t nf; /* global NF */
|
||||
uint8_t rssi; /* global RSSI */
|
||||
uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS];
|
||||
/* per-chain, per-pilot EVM values */
|
||||
};
|
||||
|
||||
#define ieee80211_input(ni, m, rssi, nf) \
|
||||
((ni)->ni_vap->iv_input(ni, m, rssi, nf))
|
||||
int ieee80211_input_all(struct ieee80211com *, struct mbuf *, int, int);
|
||||
|
||||
int ieee80211_input_mimo(struct ieee80211_node *, struct mbuf *,
|
||||
struct ieee80211_rx_stats *);
|
||||
int ieee80211_input_mimo_all(struct ieee80211com *, struct mbuf *,
|
||||
struct ieee80211_rx_stats *);
|
||||
|
||||
struct ieee80211_bpf_params;
|
||||
int ieee80211_mgmt_output(struct ieee80211_node *, struct mbuf *, int,
|
||||
struct ieee80211_bpf_params *);
|
||||
|
Loading…
Reference in New Issue
Block a user