summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2018-01-11 19:33:35 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2018-01-11 19:33:35 +0000
commit9a64ecb680341b1c05b1c4fa29903cd00bb728fd (patch)
tree7c48633afa1b7c1676b269fb231897f161d5a61a /sys/dev/ic
parent714239ddeaf485d80911e887741603f205367777 (diff)
Extract the control channel number from the chanspec information and
apply the channel to the node, like iwm(4) does, when supplying the scan response to the net80211 stack. Our stack uses this information for node selection so it's elementary for it to be correct. Tested by jcs@
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/bwfm.c106
-rw-r--r--sys/dev/ic/bwfmreg.h42
2 files changed, 145 insertions, 3 deletions
diff --git a/sys/dev/ic/bwfm.c b/sys/dev/ic/bwfm.c
index 4e7d26bdfe3..15de18146ac 100644
--- a/sys/dev/ic/bwfm.c
+++ b/sys/dev/ic/bwfm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfm.c,v 1.29 2018/01/08 23:30:11 patrick Exp $ */
+/* $OpenBSD: bwfm.c,v 1.30 2018/01/11 19:33:34 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -99,6 +99,10 @@ int bwfm_fwvar_var_set_data(struct bwfm_softc *, char *, void *, size_t);
int bwfm_fwvar_var_get_int(struct bwfm_softc *, char *, uint32_t *);
int bwfm_fwvar_var_set_int(struct bwfm_softc *, char *, uint32_t);
+uint32_t bwfm_spec2chan(struct bwfm_softc *, uint32_t);
+uint32_t bwfm_spec2chan_d11n(struct bwfm_softc *, uint32_t);
+uint32_t bwfm_spec2chan_d11ac(struct bwfm_softc *, uint32_t);
+
void bwfm_connect(struct bwfm_softc *);
#ifndef IEEE80211_STA_ONLY
void bwfm_hostap(struct bwfm_softc *);
@@ -1325,6 +1329,88 @@ bwfm_fwvar_var_set_int(struct bwfm_softc *sc, char *name, uint32_t data)
return bwfm_fwvar_var_set_data(sc, name, &data, sizeof(data));
}
+/* Channel parameters */
+uint32_t
+bwfm_spec2chan(struct bwfm_softc *sc, uint32_t chanspec)
+{
+ if (sc->sc_io_type == BWFM_IO_TYPE_D11N)
+ return bwfm_spec2chan_d11n(sc, chanspec);
+ else
+ return bwfm_spec2chan_d11ac(sc, chanspec);
+}
+
+uint32_t
+bwfm_spec2chan_d11n(struct bwfm_softc *sc, uint32_t chanspec)
+{
+ uint32_t chanidx;
+
+ chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK;
+
+ switch (chanspec & BWFM_CHANSPEC_D11N_BW_MASK) {
+ case BWFM_CHANSPEC_D11N_BW_40:
+ switch (chanspec & BWFM_CHANSPEC_D11N_SB_MASK) {
+ case BWFM_CHANSPEC_D11N_SB_L:
+ chanidx -= 2;
+ break;
+ case BWFM_CHANSPEC_D11N_SB_U:
+ chanidx += 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return chanidx;
+}
+
+uint32_t
+bwfm_spec2chan_d11ac(struct bwfm_softc *sc, uint32_t chanspec)
+{
+ uint32_t chanidx;
+
+ chanidx = chanspec & BWFM_CHANSPEC_CHAN_MASK;
+
+ switch (chanspec & BWFM_CHANSPEC_D11AC_BW_MASK) {
+ case BWFM_CHANSPEC_D11AC_BW_40:
+ switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK) {
+ case BWFM_CHANSPEC_D11AC_SB_LLL:
+ chanidx -= 2;
+ break;
+ case BWFM_CHANSPEC_D11AC_SB_LLU:
+ chanidx += 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case BWFM_CHANSPEC_D11AC_BW_80:
+ switch (chanspec & BWFM_CHANSPEC_D11AC_SB_MASK) {
+ case BWFM_CHANSPEC_D11AC_SB_LLL:
+ chanidx -= 6;
+ break;
+ case BWFM_CHANSPEC_D11AC_SB_LLU:
+ chanidx -= 2;
+ break;
+ case BWFM_CHANSPEC_D11AC_SB_LUL:
+ chanidx += 2;
+ break;
+ case BWFM_CHANSPEC_D11AC_SB_LUU:
+ chanidx += 6;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return chanidx;
+}
+
/* 802.11 code */
void
bwfm_connect(struct bwfm_softc *sc)
@@ -1849,12 +1935,14 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
- struct ieee80211_rxinfo rxi;
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
+ struct ieee80211_rxinfo rxi;
+ struct ieee80211_channel *bss_chan;
struct mbuf *m;
uint32_t pktlen, ieslen;
uint16_t iesoff;
+ int chanidx;
iesoff = letoh16(bss->ie_offset);
ieslen = letoh32(bss->ie_length);
@@ -1885,10 +1973,24 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
/* Finalize mbuf. */
m->m_pkthdr.len = m->m_len = pktlen;
ni = ieee80211_find_rxnode(ic, wh);
+ /*
+ * We may switch ic_bss's channel during scans.
+ * Record the current channel so we can restore it later.
+ */
+ bss_chan = NULL;
+ if (ni == ic->ic_bss)
+ bss_chan = ni->ni_chan;
+ /* Channel mask equals IEEE80211_CHAN_MAX */
+ chanidx = bwfm_spec2chan(sc, letoh32(bss->chanspec));
+ ni->ni_chan = &ic->ic_channels[chanidx];
+ /* Supply RSSI */
rxi.rxi_flags = 0;
rxi.rxi_rssi = letoh32(bss->rssi);
rxi.rxi_tstamp = 0;
ieee80211_input(ifp, m, ni, &rxi);
+ /* Restore channel */
+ if (bss_chan)
+ ni->ni_chan = bss_chan;
/* Node is no longer needed. */
ieee80211_release_node(ic, ni);
}
diff --git a/sys/dev/ic/bwfmreg.h b/sys/dev/ic/bwfmreg.h
index c644437e439..f0ee714712f 100644
--- a/sys/dev/ic/bwfmreg.h
+++ b/sys/dev/ic/bwfmreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfmreg.h,v 1.13 2018/01/08 23:30:11 patrick Exp $ */
+/* $OpenBSD: bwfmreg.h,v 1.14 2018/01/11 19:33:34 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -197,6 +197,46 @@
/* Channel Parameters */
#define BWFM_CHANSPEC_CHAN_MASK 0xff
#define BWFM_CHANSPEC_CHAN_SHIFT 0
+#define BWFM_CHANSPEC_D11N_SB_L (0x1 << 8) /* control lower */
+#define BWFM_CHANSPEC_D11N_SB_U (0x2 << 8) /* control lower */
+#define BWFM_CHANSPEC_D11N_SB_N (0x3 << 8) /* none */
+#define BWFM_CHANSPEC_D11N_SB_MASK (0x3 << 8)
+#define BWFM_CHANSPEC_D11N_SB_SHIFT 8
+#define BWFM_CHANSPEC_D11N_BW_10 (0x1 << 10)
+#define BWFM_CHANSPEC_D11N_BW_20 (0x2 << 10)
+#define BWFM_CHANSPEC_D11N_BW_40 (0x3 << 10)
+#define BWFM_CHANSPEC_D11N_BW_MASK (0x3 << 10)
+#define BWFM_CHANSPEC_D11N_BW_SHIFT 10
+#define BWFM_CHANSPEC_D11N_BND_5G (0x1 << 12)
+#define BWFM_CHANSPEC_D11N_BND_2G (0x2 << 12)
+#define BWFM_CHANSPEC_D11N_BND_MASK (0x3 << 12)
+#define BWFM_CHANSPEC_D11N_BND_SHIFT 12
+#define BWFM_CHANSPEC_D11AC_SB_LLL (0x0 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_LLU (0x1 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_LUL (0x2 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_LUU (0x3 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_ULL (0x4 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_ULU (0x5 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_UUL (0x6 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_UUU (0x7 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_MASK (0x7 << 8)
+#define BWFM_CHANSPEC_D11AC_SB_SHIFT 8
+#define BWFM_CHANSPEC_D11AC_BW_5 (0x0 << 11)
+#define BWFM_CHANSPEC_D11AC_BW_10 (0x1 << 11)
+#define BWFM_CHANSPEC_D11AC_BW_20 (0x2 << 11)
+#define BWFM_CHANSPEC_D11AC_BW_40 (0x3 << 11)
+#define BWFM_CHANSPEC_D11AC_BW_80 (0x4 << 11)
+#define BWFM_CHANSPEC_D11AC_BW_160 (0x5 << 11)
+#define BWFM_CHANSPEC_D11AC_BW_8080 (0x6 << 11)
+#define BWFM_CHANSPEC_D11AC_BW_MASK (0x7 << 11)
+#define BWFM_CHANSPEC_D11AC_BW_SHIFT 11
+#define BWFM_CHANSPEC_D11AC_BND_2G (0x0 << 14)
+#define BWFM_CHANSPEC_D11AC_BND_3G (0x1 << 14)
+#define BWFM_CHANSPEC_D11AC_BND_4G (0x2 << 14)
+#define BWFM_CHANSPEC_D11AC_BND_5G (0x3 << 14)
+#define BWFM_CHANSPEC_D11AC_BND_MASK (0x3 << 14)
+#define BWFM_CHANSPEC_D11AC_BND_SHIFT 14
+
#define BWFM_BAND_AUTO 0
#define BWFM_BAND_5G 1
#define BWFM_BAND_2G 2