diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2018-05-23 14:10:49 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2018-05-23 14:10:49 +0000 |
commit | 34617f99689d4d512fad5f06b4c8b3156bb3e98e (patch) | |
tree | e81cb49d47b8fee4d1e35b94502f22a33a1526a4 /sys | |
parent | 2b947a2bc09d67a82601158f79007ea4fe7ad630 (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.c | 67 |
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), |