summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2018-05-23 14:10:49 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2018-05-23 14:10:49 +0000
commit34617f99689d4d512fad5f06b4c8b3156bb3e98e (patch)
treee81cb49d47b8fee4d1e35b94502f22a33a1526a4 /sys
parent2b947a2bc09d67a82601158f79007ea4fe7ad630 (diff)
Select correct channel in Host AP mode. One part of that is creating
the channel specification (channel, freq, bandwidth, control channel) which is parsed and understood by the bwfm(4) firmware. Another part is that we shouldn't start a scan if the channel is selected by the user, otherwise we override the chosen channel. The remaining part is bringing the device down properly. If it's not disabled properly, we cannot bring it up again. ok stsp@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/bwfm.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/sys/dev/ic/bwfm.c b/sys/dev/ic/bwfm.c
index 63af1755fc7..b87f619caf8 100644
--- a/sys/dev/ic/bwfm.c
+++ b/sys/dev/ic/bwfm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfm.c,v 1.46 2018/05/23 11:32:14 patrick Exp $ */
+/* $OpenBSD: bwfm.c,v 1.47 2018/05/23 14:10:48 patrick Exp $ */
/*
* Copyright (c) 2010-2016 Broadcom Corporation
* Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -102,6 +102,9 @@ 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_chan2spec(struct bwfm_softc *, struct ieee80211_channel *);
+uint32_t bwfm_chan2spec_d11n(struct bwfm_softc *, struct ieee80211_channel *);
+uint32_t bwfm_chan2spec_d11ac(struct bwfm_softc *, struct ieee80211_channel *);
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);
@@ -386,6 +389,9 @@ bwfm_init(struct ifnet *ifp)
sc->sc_initialized = 1;
}
+ /* Select default channel */
+ ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+
if (bwfm_fwvar_var_set_int(sc, "mpc", 1)) {
printf("%s: could not set mpc\n", DEVNAME(sc));
return;
@@ -505,6 +511,7 @@ bwfm_stop(struct ifnet *ifp)
{
struct bwfm_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
+ struct bwfm_join_params join;
sc->sc_tx_timer = 0;
ifp->if_timer = 0;
@@ -513,8 +520,13 @@ bwfm_stop(struct ifnet *ifp)
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+ memset(&join, 0, sizeof(join));
+ bwfm_fwvar_cmd_set_data(sc, BWFM_C_SET_SSID, &join, sizeof(join));
bwfm_fwvar_cmd_set_int(sc, BWFM_C_DOWN, 1);
- bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_CAM);
+ bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 0);
+ bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 0);
+ bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1);
+ bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_PM, BWFM_PM_FAST_PS);
if (sc->sc_bus_ops->bs_stop)
sc->sc_bus_ops->bs_stop(sc);
@@ -1526,6 +1538,47 @@ bwfm_fwvar_var_set_int(struct bwfm_softc *sc, char *name, uint32_t data)
/* Channel parameters */
uint32_t
+bwfm_chan2spec(struct bwfm_softc *sc, struct ieee80211_channel *c)
+{
+ if (sc->sc_io_type == BWFM_IO_TYPE_D11N)
+ return bwfm_chan2spec_d11n(sc, c);
+ else
+ return bwfm_chan2spec_d11ac(sc, c);
+}
+
+uint32_t
+bwfm_chan2spec_d11n(struct bwfm_softc *sc, struct ieee80211_channel *c)
+{
+ uint32_t chanspec;
+
+ chanspec = ieee80211_mhz2ieee(c->ic_freq, 0) & BWFM_CHANSPEC_CHAN_MASK;
+ chanspec |= BWFM_CHANSPEC_D11N_SB_N;
+ chanspec |= BWFM_CHANSPEC_D11N_BW_20;
+ if (IEEE80211_IS_CHAN_2GHZ(c))
+ chanspec |= BWFM_CHANSPEC_D11N_BND_2G;
+ if (IEEE80211_IS_CHAN_5GHZ(c))
+ chanspec |= BWFM_CHANSPEC_D11N_BND_5G;
+
+ return chanspec;
+}
+
+uint32_t
+bwfm_chan2spec_d11ac(struct bwfm_softc *sc, struct ieee80211_channel *c)
+{
+ uint32_t chanspec;
+
+ chanspec = ieee80211_mhz2ieee(c->ic_freq, 0) & BWFM_CHANSPEC_CHAN_MASK;
+ chanspec |= BWFM_CHANSPEC_D11AC_SB_LLL;
+ chanspec |= BWFM_CHANSPEC_D11AC_BW_20;
+ if (IEEE80211_IS_CHAN_2GHZ(c))
+ chanspec |= BWFM_CHANSPEC_D11AC_BND_2G;
+ if (IEEE80211_IS_CHAN_5GHZ(c))
+ chanspec |= BWFM_CHANSPEC_D11AC_BND_5G;
+
+ return chanspec;
+}
+
+uint32_t
bwfm_spec2chan(struct bwfm_softc *sc, uint32_t chanspec)
{
if (sc->sc_io_type == BWFM_IO_TYPE_D11N)
@@ -1744,6 +1797,8 @@ bwfm_hostap(struct bwfm_softc *sc)
bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_INFRA, 1);
bwfm_fwvar_cmd_set_int(sc, BWFM_C_SET_AP, 1);
+ bwfm_fwvar_var_set_int(sc, "chanspec",
+ bwfm_chan2spec(sc, ic->ic_bss->ni_chan));
bwfm_fwvar_cmd_set_int(sc, BWFM_C_UP, 1);
memset(&join, 0, sizeof(join));
@@ -2375,6 +2430,14 @@ bwfm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
switch (nstate) {
case IEEE80211_S_SCAN:
+#ifndef IEEE80211_STA_ONLY
+ /* Don't start a scan if we already have a channel. */
+ if (ic->ic_state == IEEE80211_S_INIT &&
+ ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ ic->ic_des_chan != IEEE80211_CHAN_ANYC) {
+ break;
+ }
+#endif
bwfm_scan(sc);
if (ifp->if_flags & IFF_DEBUG)
printf("%s: %s -> %s\n", DEVNAME(sc),