summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2015-05-25 16:37:41 +0000
committeradrian <adrian@FreeBSD.org>2015-05-25 16:37:41 +0000
commit7eab7c352d851f4be4075556f422ac25a0e35992 (patch)
tree9a3a82a41771917c3bdebe5b898d1691fa14c9d8 /sys/net80211
parent375c3709be867b933907b85a842b7e9c66aaa13e (diff)
downloadFreeBSD-src-7eab7c352d851f4be4075556f422ac25a0e35992.zip
FreeBSD-src-7eab7c352d851f4be4075556f422ac25a0e35992.tar.gz
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.
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211.c69
-rw-r--r--sys/net80211/ieee80211_adhoc.c29
-rw-r--r--sys/net80211/ieee80211_hostap.c13
-rw-r--r--sys/net80211/ieee80211_input.c10
-rw-r--r--sys/net80211/ieee80211_input.h1
-rw-r--r--sys/net80211/ieee80211_mesh.c23
-rw-r--r--sys/net80211/ieee80211_monitor.c5
-rw-r--r--sys/net80211/ieee80211_proto.h7
-rw-r--r--sys/net80211/ieee80211_sta.c31
-rw-r--r--sys/net80211/ieee80211_tdma.c9
-rw-r--r--sys/net80211/ieee80211_tdma.h3
-rw-r--r--sys/net80211/ieee80211_var.h10
-rw-r--r--sys/net80211/ieee80211_wds.c16
13 files changed, 174 insertions, 52 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c
index 6609f46..8596ce1 100644
--- a/sys/net80211/ieee80211.c
+++ b/sys/net80211/ieee80211.c
@@ -1005,6 +1005,75 @@ ieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags)
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
addmedia(struct ifmedia *media, int caps, int addsta, int mode, int mword)
{
diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c
index 0d761c4..d31ad9b 100644
--- a/sys/net80211/ieee80211_adhoc.c
+++ b/sys/net80211/ieee80211_adhoc.c
@@ -70,11 +70,12 @@ __FBSDID("$FreeBSD$");
static void adhoc_vattach(struct ieee80211vap *);
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 *,
- int subtype, int, int);
+ int subtype, const struct ieee80211_rx_stats *, int, int);
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);
void
@@ -289,7 +290,8 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer.
*/
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 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 */
goto out;
}
- vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+ vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out;
case IEEE80211_FC0_TYPE_CTL:
@@ -687,10 +689,11 @@ is11bclient(const uint8_t *rates, const uint8_t *xrates)
static void
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 ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_channel *rxchan = ic->ic_curchan;
struct ieee80211_frame *wh;
uint8_t *frm, *efrm, *sfrm;
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_BEACON: {
struct ieee80211_scanparams scan;
+ struct ieee80211_channel *c;
/*
* We process beacon/probe response
* 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;
/*
* 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);
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);
return;
}
@@ -911,7 +920,7 @@ adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
static void
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 ieee80211com *ic = ni->ni_ic;
@@ -922,7 +931,7 @@ ahdemo_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* a site-survey.
*/
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 {
wh = mtod(m0, struct ieee80211_frame *);
switch (subtype) {
diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c
index a625b4e..f96fb2c 100644
--- a/sys/net80211/ieee80211_hostap.c
+++ b/sys/net80211/ieee80211_hostap.c
@@ -68,11 +68,12 @@ __FBSDID("$FreeBSD$");
static void hostap_vattach(struct ieee80211vap *);
static int hostap_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static int hostap_input(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_rx_stats *,
int rssi, int nf);
static void hostap_deliver_data(struct ieee80211vap *,
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);
void
@@ -476,7 +477,8 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer.
*/
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 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))
ieee80211_radiotap_rx(vap, m);
need_tap = 0;
- vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+ vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out;
case IEEE80211_FC0_TYPE_CTL:
@@ -1681,7 +1683,7 @@ is11bclient(const uint8_t *rates, const uint8_t *xrates)
static void
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 ieee80211com *ic = ni->ni_ic;
@@ -1709,7 +1711,8 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
return;
}
/* 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;
/*
* Count frame now that we know it's to be processed.
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index a0f737d..9f3fad3 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -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 */
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
@@ -468,7 +469,7 @@ ieee80211_alloc_challenge(struct ieee80211_node *ni)
*/
int
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 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->bintval = 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->ies = frm;
scan->ies_len = efrm - frm;
@@ -648,7 +649,8 @@ ieee80211_parse_beacon(struct ieee80211_node *ni, struct mbuf *m,
*/
IEEE80211_DISCARD(vap,
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++;
scan->status |= IEEE80211_BPARSE_OFFCHAN;
}
diff --git a/sys/net80211/ieee80211_input.h b/sys/net80211/ieee80211_input.h
index f3d569e..72fd25b 100644
--- a/sys/net80211/ieee80211_input.h
+++ b/sys/net80211/ieee80211_input.h
@@ -255,6 +255,7 @@ void ieee80211_send_error(struct ieee80211_node *,
const uint8_t mac[IEEE80211_ADDR_LEN], int subtype, int arg);
int ieee80211_alloc_challenge(struct ieee80211_node *);
int ieee80211_parse_beacon(struct ieee80211_node *, struct mbuf *,
+ struct ieee80211_channel *,
struct ieee80211_scanparams *);
int ieee80211_parse_action(struct ieee80211_node *, struct mbuf *);
#endif /* _NET80211_IEEE80211_INPUT_H_ */
diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c
index 5ffd50b..225a507 100644
--- a/sys/net80211/ieee80211_mesh.c
+++ b/sys/net80211/ieee80211_mesh.c
@@ -85,9 +85,10 @@ static void mesh_transmit_to_gate(struct ieee80211vap *, struct mbuf *,
struct ieee80211_mesh_route *);
static void mesh_forward(struct ieee80211vap *, struct mbuf *,
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,
- int, int);
+ const struct ieee80211_rx_stats *rxs, int, 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_backoff(struct ieee80211_node *);
@@ -1532,7 +1533,8 @@ mesh_recv_group_data(struct ieee80211vap *vap, struct mbuf *m,
}
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 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 */
goto out;
}
- vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+ vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out;
case IEEE80211_FC0_TYPE_CTL:
vap->iv_stats.is_rx_ctl++;
@@ -1859,11 +1861,12 @@ out:
static void
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 ieee80211_mesh_state *ms = vap->iv_mesh;
struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_channel *rxchan = ic->ic_curchan;
struct ieee80211_frame *wh;
struct ieee80211_mesh_route *rt;
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:
{
struct ieee80211_scanparams scan;
+ struct ieee80211_channel *c;
/*
* We process beacon/probe response
* 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;
/*
* 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);
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);
return;
}
diff --git a/sys/net80211/ieee80211_monitor.c b/sys/net80211/ieee80211_monitor.c
index 8909339..e077846 100644
--- a/sys/net80211/ieee80211_monitor.c
+++ b/sys/net80211/ieee80211_monitor.c
@@ -61,7 +61,7 @@ __FBSDID("$FreeBSD$");
static void monitor_vattach(struct ieee80211vap *);
static int monitor_newstate(struct ieee80211vap *, enum ieee80211_state, int);
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
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.
*/
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 ifnet *ifp = vap->iv_ifp;
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 3b46ac4..74cdbc5 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -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_EVM 0x0000020 /* per-chain EVM 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 {
uint32_t r_flags; /* IEEE80211_R_* flags */
@@ -80,10 +83,12 @@ struct ieee80211_rx_stats {
uint8_t rssi; /* global RSSI */
uint8_t evm[IEEE80211_MAX_CHAINS][IEEE80211_MAX_EVM_PILOTS];
/* per-chain, per-pilot EVM values */
+ uint16_t c_freq;
+ uint8_t c_ieee;
};
#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_mimo(struct ieee80211_node *, struct mbuf *,
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 267ad11..424aac8 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -70,9 +70,10 @@ __FBSDID("$FreeBSD$");
static void sta_vattach(struct ieee80211vap *);
static void sta_beacon_miss(struct ieee80211vap *);
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 *,
- 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);
void
@@ -525,7 +526,8 @@ doprint(struct ieee80211vap *vap, int subtype)
* by the 802.11 layer.
*/
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 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->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;
case IEEE80211_FC0_TYPE_CTL:
@@ -1285,13 +1287,15 @@ startbgscan(struct ieee80211vap *vap)
}
static void
-sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
- int subtype, int rssi, int nf)
+sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
+ const struct ieee80211_rx_stats *rxs,
+ int rssi, int nf)
{
#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
#define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP)
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211_channel *rxchan = ic->ic_curchan;
struct ieee80211_frame *wh;
uint8_t *frm, *efrm;
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_BEACON: {
struct ieee80211_scanparams scan;
+ struct ieee80211_channel *c;
/*
* We process beacon/probe response frames:
* o when scanning, or
@@ -1316,8 +1321,16 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
vap->iv_stats.is_rx_mgtdiscard++;
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? */
- if (ieee80211_parse_beacon(ni, m0, &scan) != 0) {
+ if (ieee80211_parse_beacon(ni, m0, rxchan, &scan) != 0) {
if (! (ic->ic_flags & IEEE80211_F_SCAN))
vap->iv_stats.is_beacon_bad++;
return;
@@ -1484,7 +1497,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
* our ap.
*/
if (ic->ic_flags & IEEE80211_F_SCAN) {
- ieee80211_add_scan(vap, ic->ic_curchan,
+ ieee80211_add_scan(vap, rxchan,
&scan, wh, subtype, rssi, nf);
} else if (contbgscan(vap)) {
ieee80211_bg_scan(vap, 0);
@@ -1529,7 +1542,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
ieee80211_probe_curchan(vap, 1);
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);
return;
}
diff --git a/sys/net80211/ieee80211_tdma.c b/sys/net80211/ieee80211_tdma.c
index 08acc38..d9ee464 100644
--- a/sys/net80211/ieee80211_tdma.c
+++ b/sys/net80211/ieee80211_tdma.c
@@ -115,7 +115,7 @@ static void tdma_vdetach(struct ieee80211vap *vap);
static int tdma_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void tdma_beacon_miss(struct ieee80211vap *vap);
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,
const struct ieee80211_tdma_param *tdma, struct ieee80211_node *ni,
int pickslot);
@@ -320,7 +320,7 @@ tdma_beacon_miss(struct ieee80211vap *vap)
static void
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 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_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;
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
*/
}
- ts->tdma_recv_mgmt(ni, m0, subtype, rssi, nf);
+ ts->tdma_recv_mgmt(ni, m0, subtype, rxs, rssi, nf);
}
/*
diff --git a/sys/net80211/ieee80211_tdma.h b/sys/net80211/ieee80211_tdma.h
index 2fe591f..76b9ed1 100644
--- a/sys/net80211/ieee80211_tdma.h
+++ b/sys/net80211/ieee80211_tdma.h
@@ -81,7 +81,8 @@ struct ieee80211_tdma_state {
int (*tdma_newstate)(struct ieee80211vap *, enum ieee80211_state,
int arg);
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 *);
};
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index e7d2f91..4c9fbf3 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -468,9 +468,13 @@ struct ieee80211vap {
void (*iv_opdetach)(struct ieee80211vap *);
/* receive processing */
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 *,
- struct mbuf *, int, int, int);
+ struct mbuf *, int,
+ const struct ieee80211_rx_stats *,
+ int, int);
void (*iv_recv_ctl)(struct ieee80211_node *,
struct mbuf *, int);
void (*iv_deliver_data)(struct ieee80211vap *,
@@ -710,6 +714,8 @@ struct ieee80211_channel *ieee80211_find_channel(struct ieee80211com *,
int freq, int flags);
struct ieee80211_channel *ieee80211_find_channel_byieee(struct ieee80211com *,
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);
enum ieee80211_phymode ieee80211_chan2mode(const struct ieee80211_channel *);
uint32_t ieee80211_mac_hash(const struct ieee80211com *,
diff --git a/sys/net80211/ieee80211_wds.c b/sys/net80211/ieee80211_wds.c
index fc77259..1d3f30a 100644
--- a/sys/net80211/ieee80211_wds.c
+++ b/sys/net80211/ieee80211_wds.c
@@ -64,9 +64,10 @@ __FBSDID("$FreeBSD$");
static void wds_vattach(struct ieee80211vap *);
static int wds_newstate(struct ieee80211vap *, enum ieee80211_state, int);
-static int wds_input(struct ieee80211_node *ni, struct mbuf *m, int, int);
-static void wds_recv_mgmt(struct ieee80211_node *, struct mbuf *,
- int subtype, int, int);
+static int wds_input(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_rx_stats *rxs, int, int);
+static void wds_recv_mgmt(struct ieee80211_node *, struct mbuf *, int subtype,
+ const struct ieee80211_rx_stats *, int, int);
void
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.
*/
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 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 */
goto out;
}
- vap->iv_recv_mgmt(ni, m, subtype, rssi, nf);
+ vap->iv_recv_mgmt(ni, m, subtype, rxs, rssi, nf);
goto out;
case IEEE80211_FC0_TYPE_CTL:
@@ -744,8 +746,8 @@ out:
}
static void
-wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
- int subtype, int rssi, int nf)
+wds_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
+ const struct ieee80211_rx_stats *rxs, int rssi, int nf)
{
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
OpenPOWER on IntegriCloud