Begin plumbing ieee80211_rx_stats through the receive path.

Smart NICs with firmware (eg wpi, iwn, the new atheros parts, the intel 7260
series, etc) support doing a lot of things in firmware.  This includes but
isn't limited to things like scanning, sending probe requests and receiving
probe responses.  However, net80211 doesn't know about any of this - it still
drives the whole scan/probe infrastructure itself.

In order to move towards suppoting smart NICs, the receive path needs to
know about the channel/details for each received packet.  In at least
the iwn and 7260 firmware (and I believe wpi, but I haven't tried it yet)
it will do the scanning, power-save and off-channel buffering for you -
all you need to do is handle receiving beacons and probe responses on
channels that aren't what you're currently on.  However the whole receive
path is peppered with ic->ic_curchan and manual scan/powersave handling.
The beacon parsing code also checks ic->ic_curchan to determine if the
received beacon is on the correct channel or not.[1]

So:

* add freq/ieee values to ieee80211_rx_stats;
* change ieee80211_parse_beacon() to accept the 'current' channel
  as an argument;
* modify the iv_input() and iv_recv_mgmt() methods to include the rx_stats;
* add a new method - ieee80211_lookup_channel_rxstats() - that looks up
  a channel based on the contents of ieee80211_rx_stats;
* if it exists, use it in the mgmt path to switch the current channel
  (which still defaults to ic->ic_curchan) over to something determined
  by rx_stats.

This is enough to kick-start scan offload support in the Intel 7260
driver that Rui/I are working on.  It also is a good start for scan
offload support for a handful of existing NICs (wpi, iwn, some USB
parts) and it'll very likely dramatically improve stability/performance
there.  It's not the whole thing - notably, we don't need to do powersave,
we should not scan all channels, and we should leave probe request sending
to the firmware and not do it ourselves.  But, this allows for continued
development on the above features whilst actually having a somewhat
working NIC.

TODO:

* Finish tidying up how the net80211 input path works.
  Right now ieee80211_input / ieee80211_input_all act as the top-level
  that everything feeds into; it should change so the MIMO input routines
  are those and the legacy routines are phased out.

* The band selection should be done by the driver, not by the net80211
  layer.

* ieee80211_lookup_channel_rxstats() only determines 11b or 11g channels
  for now - this is enough for scanning, but not 100% true in all cases.
  If we ever need to handle off-channel scan support for things like
  static-40MHz or static-80MHz, or turbo-G, or half/quarter rates,
  then we should extend this.

[1] This is a side effect of frequency-hopping and CCK modes - you
    can receive beacons when you think you're on a different channel.
    In particular, CCK (which is used by the low 11b rates, eg beacons!)
    is decodable from adjacent channels - just at a low SNR.
    FH is a side effect of having the hardware/firmware do the frequency
    hopping - it may pick up beacons transmitted from other FH networks
    that are in a different phase of hopping frequencies.
This commit is contained in:
Adrian Chadd 2015-05-25 16:37:41 +00:00
parent 9dbbcd5d9a
commit c79f192c09
18 changed files with 185 additions and 60 deletions

View File

@ -327,7 +327,7 @@ ath_legacy_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
*/ */
void void
ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
int subtype, int rssi, int nf) int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
@ -353,7 +353,7 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
* Call up first so subsequent work can use information * Call up first so subsequent work can use information
* potentially stored in the node (e.g. for ibss merge). * potentially stored in the node (e.g. for ibss merge).
*/ */
ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rssi, nf); ATH_VAP(vap)->av_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
switch (subtype) { switch (subtype) {
case IEEE80211_FC0_SUBTYPE_BEACON: case IEEE80211_FC0_SUBTYPE_BEACON:
/* update rssi statistics for use by the hal */ /* update rssi statistics for use by the hal */

View File

@ -33,7 +33,8 @@
extern u_int32_t ath_calcrxfilter(struct ath_softc *sc); extern u_int32_t ath_calcrxfilter(struct ath_softc *sc);
extern void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, extern void ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
int subtype, int rssi, int nf); int subtype, const struct ieee80211_rx_stats *rxs,
int rssi, int nf);
#define ath_stoprecv(_sc, _dodelay) \ #define ath_stoprecv(_sc, _dodelay) \
(_sc)->sc_rx.recv_stop((_sc), (_dodelay)) (_sc)->sc_rx.recv_stop((_sc), (_dodelay))

View File

@ -481,7 +481,8 @@ struct ath_vap {
struct ath_txq av_mcastq; /* buffered mcast s/w queue */ struct ath_txq av_mcastq; /* buffered mcast s/w queue */
void (*av_recv_mgmt)(struct ieee80211_node *, void (*av_recv_mgmt)(struct ieee80211_node *,
struct mbuf *, int, int, int); struct mbuf *, int,
const struct ieee80211_rx_stats *, int, int);
int (*av_newstate)(struct ieee80211vap *, int (*av_newstate)(struct ieee80211vap *,
enum ieee80211_state, int); enum ieee80211_state, int);
void (*av_bmiss)(struct ieee80211vap *); void (*av_bmiss)(struct ieee80211vap *);

View File

@ -127,7 +127,8 @@ static int wi_newstate_sta(struct ieee80211vap *, enum ieee80211_state, int);
static int wi_newstate_hostap(struct ieee80211vap *, enum ieee80211_state, static int wi_newstate_hostap(struct ieee80211vap *, enum ieee80211_state,
int); int);
static void wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, static void wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
int subtype, int rssi, int nf); int subtype, const struct ieee80211_rx_stats *rxs,
int rssi, int nf);
static int wi_reset(struct wi_softc *); static int wi_reset(struct wi_softc *);
static void wi_watchdog(void *); static void wi_watchdog(void *);
static int wi_ioctl(struct ifnet *, u_long, caddr_t); static int wi_ioctl(struct ifnet *, u_long, caddr_t);
@ -804,7 +805,7 @@ wi_scan_end(struct ieee80211com *ic)
static void static void
wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
int subtype, int rssi, int nf) int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
@ -815,7 +816,7 @@ wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
/* NB: filter frames that trigger state changes */ /* NB: filter frames that trigger state changes */
return; return;
} }
WI_VAP(vap)->wv_recv_mgmt(ni, m, subtype, rssi, nf); WI_VAP(vap)->wv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
} }
static int static int

View File

@ -61,7 +61,7 @@ struct wi_vap {
struct ieee80211_beacon_offsets wv_bo; struct ieee80211_beacon_offsets wv_bo;
void (*wv_recv_mgmt)(struct ieee80211_node *, struct mbuf *, void (*wv_recv_mgmt)(struct ieee80211_node *, struct mbuf *,
int, int, int); int, const struct ieee80211_rx_stats *rxs, int, int);
int (*wv_newstate)(struct ieee80211vap *, int (*wv_newstate)(struct ieee80211vap *,
enum ieee80211_state, int); enum ieee80211_state, int);
}; };

View File

@ -1005,6 +1005,75 @@ ieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags)
return NULL; return NULL;
} }
/*
* Lookup a channel suitable for the given rx status.
*
* This is used to find a channel for a frame (eg beacon, probe
* response) based purely on the received PHY information.
*
* For now it tries to do it based on R_FREQ / R_IEEE.
* This is enough for 11bg and 11a (and thus 11ng/11na)
* but it will not be enough for GSM, PSB channels and the
* like. It also doesn't know about legacy-turbog and
* legacy-turbo modes, which some offload NICs actually
* support in weird ways.
*
* Takes the ic and rxstatus; returns the channel or NULL
* if not found.
*
* XXX TODO: Add support for that when the need arises.
*/
struct ieee80211_channel *
ieee80211_lookup_channel_rxstatus(struct ieee80211vap *vap,
const struct ieee80211_rx_stats *rxs)
{
struct ieee80211com *ic = vap->iv_ic;
uint32_t flags;
struct ieee80211_channel *c;
if (rxs == NULL)
return (NULL);
/*
* Strictly speaking we only use freq for now,
* however later on we may wish to just store
* the ieee for verification.
*/
if ((rxs->r_flags & IEEE80211_R_FREQ) == 0)
return (NULL);
if ((rxs->r_flags & IEEE80211_R_IEEE) == 0)
return (NULL);
/*
* If the rx status contains a valid ieee/freq, then
* ensure we populate the correct channel information
* in rxchan before passing it up to the scan infrastructure.
* Offload NICs will pass up beacons from all channels
* during background scans.
*/
/* Determine a band */
/* XXX should be done by the driver? */
if (rxs->c_freq < 3000) {
flags = IEEE80211_CHAN_B;
} else {
flags = IEEE80211_CHAN_A;
}
/* Channel lookup */
c = ieee80211_find_channel(ic, rxs->c_freq, flags);
IEEE80211_DPRINTF(vap, IEEE80211_MSG_INPUT,
"%s: freq=%d, ieee=%d, flags=0x%08x; c=%p\n",
__func__,
(int) rxs->c_freq,
(int) rxs->c_ieee,
flags,
c);
return (c);
}
static void static void
addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword) addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
{ {

View File

@ -70,11 +70,12 @@ __FBSDID("$FreeBSD$");
static void adhoc_vattach(struct ieee80211vap *); static void adhoc_vattach(struct ieee80211vap *);
static int adhoc_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int adhoc_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int adhoc_input(struct ieee80211_node *, struct mbuf *, int, int); static int adhoc_input(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_rx_stats *, int, int);
static void adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *, static void adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *,
int subtype, int, int); int subtype, const struct ieee80211_rx_stats *, int, int);
static void ahdemo_recv_mgmt(struct ieee80211_node *, struct mbuf *, static void ahdemo_recv_mgmt(struct ieee80211_node *, struct mbuf *,
int subtype, int, int); int subtype, const struct ieee80211_rx_stats *rxs, int, int);
static void adhoc_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype); static void adhoc_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
void void
@ -289,7 +290,8 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer. * by the 802.11 layer.
*/ */
static int static int
adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) adhoc_input(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
@ -642,7 +644,7 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
vap->iv_stats.is_rx_mgtdiscard++; /* XXX */ vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
goto out; goto out;
} }
vap->iv_recv_mgmt(ni, m, subtype, rssi, nf); vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out; goto out;
case IEEE80211_FC0_TYPE_CTL: case IEEE80211_FC0_TYPE_CTL:
@ -687,10 +689,11 @@ is11bclient(const uint8_t *rates, const uint8_t *xrates)
static void static void
adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
int subtype, int rssi, int nf) int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_channel *rxchan = ic->ic_curchan;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
uint8_t *frm, *efrm, *sfrm; uint8_t *frm, *efrm, *sfrm;
uint8_t *ssid, *rates, *xrates; uint8_t *ssid, *rates, *xrates;
@ -705,11 +708,17 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
case IEEE80211_FC0_SUBTYPE_PROBE_RESP: case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
case IEEE80211_FC0_SUBTYPE_BEACON: { case IEEE80211_FC0_SUBTYPE_BEACON: {
struct ieee80211_scanparams scan; struct ieee80211_scanparams scan;
struct ieee80211_channel *c;
/* /*
* We process beacon/probe response * We process beacon/probe response
* frames to discover neighbors. * frames to discover neighbors.
*/ */
if (ieee80211_parse_beacon(ni, m0, &scan) != 0) if (rxs != NULL) {
c = ieee80211_lookup_channel_rxstatus(vap, rxs);
if (c != NULL)
rxchan = c;
}
if (ieee80211_parse_beacon(ni, m0, rxchan, &scan) != 0)
return; return;
/* /*
* Count frame now that we know it's to be processed. * Count frame now that we know it's to be processed.
@ -735,7 +744,7 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
ieee80211_probe_curchan(vap, 1); ieee80211_probe_curchan(vap, 1);
ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
} }
ieee80211_add_scan(vap, ic->ic_curchan, &scan, wh, ieee80211_add_scan(vap, rxchan, &scan, wh,
subtype, rssi, nf); subtype, rssi, nf);
return; return;
} }
@ -911,7 +920,7 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
static void static void
ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
int subtype, int rssi, int nf) int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
@ -922,7 +931,7 @@ ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* a site-survey. * a site-survey.
*/ */
if (ic->ic_flags & IEEE80211_F_SCAN) if (ic->ic_flags & IEEE80211_F_SCAN)
adhoc_recv_mgmt(ni, m0, subtype, rssi, nf); adhoc_recv_mgmt(ni, m0, subtype, rxs, rssi, nf);
else { else {
wh = mtod(m0, struct ieee80211_frame *); wh = mtod(m0, struct ieee80211_frame *);
switch (subtype) { switch (subtype) {

View File

@ -68,11 +68,12 @@ __FBSDID("$FreeBSD$");
static void hostap_vattach(struct ieee80211vap *); static void hostap_vattach(struct ieee80211vap *);
static int hostap_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int hostap_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int hostap_input(struct ieee80211_node *ni, struct mbuf *m, static int hostap_input(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_rx_stats *,
int rssi, int nf); int rssi, int nf);
static void hostap_deliver_data(struct ieee80211vap *, static void hostap_deliver_data(struct ieee80211vap *,
struct ieee80211_node *, struct mbuf *); struct ieee80211_node *, struct mbuf *);
static void hostap_recv_mgmt(struct ieee80211_node *, struct mbuf *, static void hostap_recv_mgmt(struct ieee80211_node *, struct mbuf *,
int subtype, int rssi, int nf); int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf);
static void hostap_recv_ctl(struct ieee80211_node *, struct mbuf *, int); static void hostap_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
void void
@ -476,7 +477,8 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer. * by the 802.11 layer.
*/ */
static int static int
hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) hostap_input(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
@ -893,7 +895,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
if (ieee80211_radiotap_active_vap(vap)) if (ieee80211_radiotap_active_vap(vap))
ieee80211_radiotap_rx(vap, m); ieee80211_radiotap_rx(vap, m);
need_tap = 0; need_tap = 0;
vap->iv_recv_mgmt(ni, m, subtype, rssi, nf); vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out; goto out;
case IEEE80211_FC0_TYPE_CTL: case IEEE80211_FC0_TYPE_CTL:
@ -1681,7 +1683,7 @@ is11bclient(const uint8_t *rates, const uint8_t *xrates)
static void static void
hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
int subtype, int rssi, int nf) int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
@ -1709,7 +1711,8 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
return; return;
} }
/* NB: accept off-channel frames */ /* NB: accept off-channel frames */
if (ieee80211_parse_beacon(ni, m0, &scan) &~ IEEE80211_BPARSE_OFFCHAN) /* XXX TODO: use rxstatus to determine off-channel details */
if (ieee80211_parse_beacon(ni, m0, ic->ic_curchan, &scan) &~ IEEE80211_BPARSE_OFFCHAN)
return; return;
/* /*
* Count frame now that we know it's to be processed. * Count frame now that we know it's to be processed.

View File

@ -88,7 +88,8 @@ ieee80211_input_mimo(struct ieee80211_node *ni, struct mbuf *m,
{ {
/* XXX should assert IEEE80211_R_NF and IEEE80211_R_RSSI are set */ /* XXX should assert IEEE80211_R_NF and IEEE80211_R_RSSI are set */
ieee80211_process_mimo(ni, rx); ieee80211_process_mimo(ni, rx);
return ieee80211_input(ni, m, rx->rssi, rx->nf); //return ieee80211_input(ni, m, rx->rssi, rx->nf);
return ni->ni_vap->iv_input(ni, m, rx, rx->rssi, rx->nf);
} }
int int
@ -468,7 +469,7 @@ ieee80211_alloc_challenge(struct ieee80211_node *ni)
*/ */
int int
ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m, ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
struct ieee80211_scanparams *scan) struct ieee80211_channel *rxchan, struct ieee80211_scanparams *scan)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
@ -505,7 +506,7 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
scan->tstamp = frm; frm += 8; scan->tstamp = frm; frm += 8;
scan->bintval = le16toh(*(uint16_t *)frm); frm += 2; scan->bintval = le16toh(*(uint16_t *)frm); frm += 2;
scan->capinfo = le16toh(*(uint16_t *)frm); frm += 2; scan->capinfo = le16toh(*(uint16_t *)frm); frm += 2;
scan->bchan = ieee80211_chan2ieee(ic, ic->ic_curchan); scan->bchan = ieee80211_chan2ieee(ic, rxchan);
scan->chan = scan->bchan; scan->chan = scan->bchan;
scan->ies = frm; scan->ies = frm;
scan->ies_len = efrm - frm; scan->ies_len = efrm - frm;
@ -648,7 +649,8 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
*/ */
IEEE80211_DISCARD(vap, IEEE80211_DISCARD(vap,
IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
wh, NULL, "for off-channel %u", scan->chan); wh, NULL, "for off-channel %u (bchan=%u)",
scan->chan, scan->bchan);
vap->iv_stats.is_rx_chanmismatch++; vap->iv_stats.is_rx_chanmismatch++;
scan->status |= IEEE80211_BPARSE_OFFCHAN; scan->status |= IEEE80211_BPARSE_OFFCHAN;
} }

View File

@ -255,6 +255,7 @@ void ieee80211_send_error(struct ieee80211_node *,
const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg); const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg);
int ieee80211_alloc_challenge(struct ieee80211_node *); int ieee80211_alloc_challenge(struct ieee80211_node *);
int ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *, int ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *,
struct ieee80211_channel *,
struct ieee80211_scanparams *); struct ieee80211_scanparams *);
int ieee80211_parse_action(struct ieee80211_node *, struct mbuf *); int ieee80211_parse_action(struct ieee80211_node *, struct mbuf *);
#endif /* _NET80211_IEEE80211_INPUT_H_ */ #endif /* _NET80211_IEEE80211_INPUT_H_ */

View File

@ -85,9 +85,10 @@ static void mesh_transmit_to_gate(struct ieee80211vap *, struct mbuf *,
struct ieee80211_mesh_route *); struct ieee80211_mesh_route *);
static void mesh_forward(struct ieee80211vap *, struct mbuf *, static void mesh_forward(struct ieee80211vap *, struct mbuf *,
const struct ieee80211_meshcntl *); const struct ieee80211_meshcntl *);
static int mesh_input(struct ieee80211_node *, struct mbuf *, int, int); static int mesh_input(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_rx_stats *rxs, int, int);
static void mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, static void mesh_recv_mgmt(struct ieee80211_node *, struct mbuf *, int,
int, int); const struct ieee80211_rx_stats *rxs, int, int);
static void mesh_recv_ctl(struct ieee80211_node *, struct mbuf *, int); static void mesh_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
static void mesh_peer_timeout_setup(struct ieee80211_node *); static void mesh_peer_timeout_setup(struct ieee80211_node *);
static void mesh_peer_timeout_backoff(struct ieee80211_node *); static void mesh_peer_timeout_backoff(struct ieee80211_node *);
@ -1532,7 +1533,8 @@ mesh_recv_group_data(struct ieee80211vap *vap, struct mbuf *m,
} }
static int static int
mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) mesh_input(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
#define HAS_SEQ(type) ((type & 0x4) == 0) #define HAS_SEQ(type) ((type & 0x4) == 0)
#define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc) #define MC01(mc) ((const struct ieee80211_meshcntl_ae01 *)mc)
@ -1831,7 +1833,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
vap->iv_stats.is_rx_mgtdiscard++; /* XXX */ vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
goto out; goto out;
} }
vap->iv_recv_mgmt(ni, m, subtype, rssi, nf); vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out; goto out;
case IEEE80211_FC0_TYPE_CTL: case IEEE80211_FC0_TYPE_CTL:
vap->iv_stats.is_rx_ctl++; vap->iv_stats.is_rx_ctl++;
@ -1859,11 +1861,12 @@ out:
static void static void
mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype, mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
int rssi, int nf) const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_mesh_state *ms = vap->iv_mesh; struct ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_channel *rxchan = ic->ic_curchan;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
struct ieee80211_mesh_route *rt; struct ieee80211_mesh_route *rt;
uint8_t *frm, *efrm; uint8_t *frm, *efrm;
@ -1876,11 +1879,17 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
case IEEE80211_FC0_SUBTYPE_BEACON: case IEEE80211_FC0_SUBTYPE_BEACON:
{ {
struct ieee80211_scanparams scan; struct ieee80211_scanparams scan;
struct ieee80211_channel *c;
/* /*
* We process beacon/probe response * We process beacon/probe response
* frames to discover neighbors. * frames to discover neighbors.
*/ */
if (ieee80211_parse_beacon(ni, m0, &scan) != 0) if (rxs != NULL) {
c = ieee80211_lookup_channel_rxstatus(vap, rxs);
if (c != NULL)
rxchan = c;
}
if (ieee80211_parse_beacon(ni, m0, rxchan, &scan) != 0)
return; return;
/* /*
* Count frame now that we know it's to be processed. * Count frame now that we know it's to be processed.
@ -1906,7 +1915,7 @@ mesh_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
ieee80211_probe_curchan(vap, 1); ieee80211_probe_curchan(vap, 1);
ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
} }
ieee80211_add_scan(vap, ic->ic_curchan, &scan, wh, ieee80211_add_scan(vap, rxchan, &scan, wh,
subtype, rssi, nf); subtype, rssi, nf);
return; return;
} }

View File

@ -61,7 +61,7 @@ __FBSDID("$FreeBSD$");
static void monitor_vattach(struct ieee80211vap *); static void monitor_vattach(struct ieee80211vap *);
static int monitor_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int monitor_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int monitor_input(struct ieee80211_node *ni, struct mbuf *m, static int monitor_input(struct ieee80211_node *ni, struct mbuf *m,
int rssi, int nf); const struct ieee80211_rx_stats *rxs, int rssi, int nf);
void void
ieee80211_monitor_attach(struct ieee80211com *ic) ieee80211_monitor_attach(struct ieee80211com *ic)
@ -125,7 +125,8 @@ monitor_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* Process a received frame in monitor mode. * Process a received frame in monitor mode.
*/ */
static int static int
monitor_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) monitor_input(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ifnet *ifp = vap->iv_ifp; struct ifnet *ifp = vap->iv_ifp;

View File

@ -68,6 +68,9 @@ void ieee80211_syncflag_ext(struct ieee80211vap *, int flag);
#define IEEE80211_R_C_RSSI 0x0000010 /* per-chain RSSI 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_EVM 0x0000020 /* per-chain EVM valid */
#define IEEE80211_R_C_HT40 0x0000040 /* RX'ed packet is 40mhz, pilots 4,5 valid */ #define IEEE80211_R_C_HT40 0x0000040 /* RX'ed packet is 40mhz, pilots 4,5 valid */
#define IEEE80211_R_FREQ 0x0000080 /* Freq value populated, MHz */
#define IEEE80211_R_IEEE 0x0000100 /* IEEE value populated */
#define IEEE80211_R_BAND 0x0000200 /* Frequency band populated */
struct ieee80211_rx_stats { struct ieee80211_rx_stats {
uint32_t r_flags; /* IEEE80211_R_* flags */ uint32_t r_flags; /* IEEE80211_R_* flags */
@ -80,10 +83,12 @@ struct ieee80211_rx_stats {
uint8_t rssi; /* global RSSI */ uint8_t rssi; /* global RSSI */
uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS]; uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS];
/* per-chain, per-pilot EVM values */ /* per-chain, per-pilot EVM values */
uint16_t c_freq;
uint8_t c_ieee;
}; };
#define ieee80211_input(ni, m, rssi, nf) \ #define ieee80211_input(ni, m, rssi, nf) \
((ni)->ni_vap->iv_input(ni, m, rssi, nf)) ((ni)->ni_vap->iv_input(ni, m, NULL, rssi, nf))
int ieee80211_input_all(struct ieee80211com *, struct mbuf *, int, int); int ieee80211_input_all(struct ieee80211com *, struct mbuf *, int, int);
int ieee80211_input_mimo(struct ieee80211_node *, struct mbuf *, int ieee80211_input_mimo(struct ieee80211_node *, struct mbuf *,

View File

@ -70,9 +70,10 @@ __FBSDID("$FreeBSD$");
static void sta_vattach(struct ieee80211vap *); static void sta_vattach(struct ieee80211vap *);
static void sta_beacon_miss(struct ieee80211vap *); static void sta_beacon_miss(struct ieee80211vap *);
static int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int sta_input(struct ieee80211_node *, struct mbuf *, int, int); static int sta_input(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_rx_stats *, int, int);
static void sta_recv_mgmt(struct ieee80211_node *, struct mbuf *, static void sta_recv_mgmt(struct ieee80211_node *, struct mbuf *,
int subtype, int rssi, int nf); int subtype, const struct ieee80211_rx_stats *, int rssi, int nf);
static void sta_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype); static void sta_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype);
void void
@ -525,7 +526,8 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer. * by the 802.11 layer.
*/ */
static int static int
sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) sta_input(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
@ -922,7 +924,7 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
wh = mtod(m, struct ieee80211_frame *); wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
} }
vap->iv_recv_mgmt(ni, m, subtype, rssi, nf); vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out; goto out;
case IEEE80211_FC0_TYPE_CTL: case IEEE80211_FC0_TYPE_CTL:
@ -1285,13 +1287,15 @@ startbgscan(struct ieee80211vap *vap)
} }
static void static void
sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
int subtype, int rssi, int nf) const struct ieee80211_rx_stats *rxs,
int rssi, int nf)
{ {
#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP) #define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
#define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP) #define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_channel *rxchan = ic->ic_curchan;
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
uint8_t *frm, *efrm; uint8_t *frm, *efrm;
uint8_t *rates, *xrates, *wme, *htcap, *htinfo; uint8_t *rates, *xrates, *wme, *htcap, *htinfo;
@ -1305,6 +1309,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
case IEEE80211_FC0_SUBTYPE_PROBE_RESP: case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
case IEEE80211_FC0_SUBTYPE_BEACON: { case IEEE80211_FC0_SUBTYPE_BEACON: {
struct ieee80211_scanparams scan; struct ieee80211_scanparams scan;
struct ieee80211_channel *c;
/* /*
* We process beacon/probe response frames: * We process beacon/probe response frames:
* o when scanning, or * o when scanning, or
@ -1316,8 +1321,16 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
vap->iv_stats.is_rx_mgtdiscard++; vap->iv_stats.is_rx_mgtdiscard++;
return; return;
} }
/* Override RX channel as appropriate */
if (rxs != NULL) {
c = ieee80211_lookup_channel_rxstatus(vap, rxs);
if (c != NULL)
rxchan = c;
}
/* XXX probe response in sta mode when !scanning? */ /* XXX probe response in sta mode when !scanning? */
if (ieee80211_parse_beacon(ni, m0, &scan) != 0) { if (ieee80211_parse_beacon(ni, m0, rxchan, &scan) != 0) {
if (! (ic->ic_flags & IEEE80211_F_SCAN)) if (! (ic->ic_flags & IEEE80211_F_SCAN))
vap->iv_stats.is_beacon_bad++; vap->iv_stats.is_beacon_bad++;
return; return;
@ -1484,7 +1497,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* our ap. * our ap.
*/ */
if (ic->ic_flags & IEEE80211_F_SCAN) { if (ic->ic_flags & IEEE80211_F_SCAN) {
ieee80211_add_scan(vap, ic->ic_curchan, ieee80211_add_scan(vap, rxchan,
&scan, wh, subtype, rssi, nf); &scan, wh, subtype, rssi, nf);
} else if (contbgscan(vap)) { } else if (contbgscan(vap)) {
ieee80211_bg_scan(vap, 0); ieee80211_bg_scan(vap, 0);
@ -1529,7 +1542,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
ieee80211_probe_curchan(vap, 1); ieee80211_probe_curchan(vap, 1);
ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN;
} }
ieee80211_add_scan(vap, ic->ic_curchan, &scan, wh, ieee80211_add_scan(vap, rxchan, &scan, wh,
subtype, rssi, nf); subtype, rssi, nf);
return; return;
} }

View File

@ -115,7 +115,7 @@ static void tdma_vdetach(struct ieee80211vap *vap);
static int tdma_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int tdma_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void tdma_beacon_miss(struct ieee80211vap *vap); static void tdma_beacon_miss(struct ieee80211vap *vap);
static void tdma_recv_mgmt(struct ieee80211_node *, struct mbuf *, static void tdma_recv_mgmt(struct ieee80211_node *, struct mbuf *,
int subtype, int rssi, int nf); int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf);
static int tdma_update(struct ieee80211vap *vap, static int tdma_update(struct ieee80211vap *vap,
const struct ieee80211_tdma_param *tdma, struct ieee80211_node *ni, const struct ieee80211_tdma_param *tdma, struct ieee80211_node *ni,
int pickslot); int pickslot);
@ -320,7 +320,7 @@ tdma_beacon_miss(struct ieee80211vap *vap)
static void static void
tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
int subtype, int rssi, int nf) int subtype, const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
@ -331,7 +331,8 @@ tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *); struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *);
struct ieee80211_scanparams scan; struct ieee80211_scanparams scan;
if (ieee80211_parse_beacon(ni, m0, &scan) != 0) /* XXX TODO: use rxstatus to determine off-channel beacons */
if (ieee80211_parse_beacon(ni, m0, ic->ic_curchan, &scan) != 0)
return; return;
if (scan.tdma == NULL) { if (scan.tdma == NULL) {
/* /*
@ -391,7 +392,7 @@ tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* 2x parsing of the frame but should happen infrequently * 2x parsing of the frame but should happen infrequently
*/ */
} }
ts->tdma_recv_mgmt(ni, m0, subtype, rssi, nf); ts->tdma_recv_mgmt(ni, m0, subtype, rxs, rssi, nf);
} }
/* /*

View File

@ -81,7 +81,8 @@ struct ieee80211_tdma_state {
int (*tdma_newstate)(struct ieee80211vap *, enum ieee80211_state, int (*tdma_newstate)(struct ieee80211vap *, enum ieee80211_state,
int arg); int arg);
void (*tdma_recv_mgmt)(struct ieee80211_node *, void (*tdma_recv_mgmt)(struct ieee80211_node *,
struct mbuf *, int, int, int); struct mbuf *, int,
const struct ieee80211_rx_stats *rxs, int, int);
void (*tdma_opdetach)(struct ieee80211vap *); void (*tdma_opdetach)(struct ieee80211vap *);
}; };

View File

@ -468,9 +468,13 @@ struct ieee80211vap {
void (*iv_opdetach)(struct ieee80211vap *); void (*iv_opdetach)(struct ieee80211vap *);
/* receive processing */ /* receive processing */
int (*iv_input)(struct ieee80211_node *, int (*iv_input)(struct ieee80211_node *,
struct mbuf *, int, int); struct mbuf *,
const struct ieee80211_rx_stats *,
int, int);
void (*iv_recv_mgmt)(struct ieee80211_node *, void (*iv_recv_mgmt)(struct ieee80211_node *,
struct mbuf *, int, int, int); struct mbuf *, int,
const struct ieee80211_rx_stats *,
int, int);
void (*iv_recv_ctl)(struct ieee80211_node *, void (*iv_recv_ctl)(struct ieee80211_node *,
struct mbuf *, int); struct mbuf *, int);
void (*iv_deliver_data)(struct ieee80211vap *, void (*iv_deliver_data)(struct ieee80211vap *,
@ -710,6 +714,8 @@ struct ieee80211_channel *ieee80211_find_channel(struct ieee80211com *,
int freq, int flags); int freq, int flags);
struct ieee80211_channel *ieee80211_find_channel_byieee(struct ieee80211com *, struct ieee80211_channel *ieee80211_find_channel_byieee(struct ieee80211com *,
int ieee, int flags); int ieee, int flags);
struct ieee80211_channel *ieee80211_lookup_channel_rxstatus(struct ieee80211vap *,
const struct ieee80211_rx_stats *);
int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode);
enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *); enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *);
uint32_t ieee80211_mac_hash(const struct ieee80211com *, uint32_t ieee80211_mac_hash(const struct ieee80211com *,

View File

@ -64,9 +64,10 @@ __FBSDID("$FreeBSD$");
static void wds_vattach(struct ieee80211vap *); static void wds_vattach(struct ieee80211vap *);
static int wds_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int wds_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int wds_input(struct ieee80211_node *ni, struct mbuf *m, int, int); static int wds_input(struct ieee80211_node *ni, struct mbuf *m,
static void wds_recv_mgmt(struct ieee80211_node *, struct mbuf *, const struct ieee80211_rx_stats *rxs, int, int);
int subtype, int, int); static void wds_recv_mgmt(struct ieee80211_node *, struct mbuf *, int subtype,
const struct ieee80211_rx_stats *, int, int);
void void
ieee80211_wds_attach(struct ieee80211com *ic) ieee80211_wds_attach(struct ieee80211com *ic)
@ -408,7 +409,8 @@ wds_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* by the 802.11 layer. * by the 802.11 layer.
*/ */
static int static int
wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) wds_input(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;
@ -718,7 +720,7 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
vap->iv_stats.is_rx_mgtdiscard++; /* XXX */ vap->iv_stats.is_rx_mgtdiscard++; /* XXX */
goto out; goto out;
} }
vap->iv_recv_mgmt(ni, m, subtype, rssi, nf); vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out; goto out;
case IEEE80211_FC0_TYPE_CTL: case IEEE80211_FC0_TYPE_CTL:
@ -744,8 +746,8 @@ out:
} }
static void static void
wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
int subtype, int rssi, int nf) const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic; struct ieee80211com *ic = ni->ni_ic;