--- a/net80211/ieee80211.c +++ b/net80211/ieee80211.c @@ -270,6 +270,7 @@ ieee80211_ifattach(struct ieee80211com * ("invalid number of channels specified: %u", ic->ic_nchans)); memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); ic->ic_modecaps |= 1 << IEEE80211_MODE_AUTO; + ic->ic_max_txpower = IEEE80211_TXPOWER_MIN; for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; @@ -277,6 +278,7 @@ ieee80211_ifattach(struct ieee80211com * KASSERT(c->ic_ieee < IEEE80211_CHAN_MAX, ("channel with bogus ieee number %u", c->ic_ieee)); setbit(ic->ic_chan_avail, c->ic_ieee); + ic->ic_max_txpower = max(ic->ic_max_txpower, (u16) (c->ic_maxpower * 2)); if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT) c->ic_scanflags |= IEEE80211_NOSCAN_SET; @@ -346,8 +348,6 @@ ieee80211_ifattach(struct ieee80211com * TAILQ_INIT(&ic->ic_vaps); ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; - ic->ic_txpowlimit = IEEE80211_TXPOWER_MIN; - ic->ic_newtxpowlimit = IEEE80211_TXPOWER_MAX; init_timer(&ic->ic_dfs_excl_timer); ic->ic_dfs_excl_timer.function = --- a/net80211/ieee80211_node.c +++ b/net80211/ieee80211_node.c @@ -1125,7 +1125,7 @@ ieee80211_alloc_node(struct ieee80211vap ni->ni_chan = IEEE80211_CHAN_ANYC; ni->ni_authmode = IEEE80211_AUTH_OPEN; - ni->ni_txpower = ic->ic_txpowlimit; + ni->ni_txpower = IEEE80211_TXPOWER_MAX; ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); --- a/net80211/ieee80211_var.h +++ b/net80211/ieee80211_var.h @@ -343,8 +343,9 @@ struct ieee80211com { u_int16_t ic_holdover; /* PM hold over duration */ u_int16_t ic_bmissthreshold; /* beacon miss threshold (# beacons) */ unsigned long ic_bmiss_guard; /* when to cease ignoring bmiss (jiffies) */ - u_int16_t ic_txpowlimit; /* global tx power limit (in 0.5 dBm) */ - u_int16_t ic_newtxpowlimit; /* tx power limit to change to (in 0.5 dBm) */ + u_int16_t ic_txpowlimit; /* configured global tx power limit (in 0.5 dBm) */ + u_int16_t ic_max_txpower; /* global hardware tx power limit */ + u_int16_t ic_cur_txpower; /* current tx power */ u_int16_t ic_uapsdmaxtriggers; /* max triggers that could arrive */ u_int8_t ic_coverageclass; /* coverage class */ u_int8_t ic_protmode_rssi; /* rssi threshold for protection mode */ --- a/net80211/ieee80211_wireless.c +++ b/net80211/ieee80211_wireless.c @@ -920,17 +920,23 @@ ieee80211_ioctl_giwrange(struct net_devi u_int8_t reported[IEEE80211_CHAN_BYTES]; /* XXX stack usage? */ int i, r; int step = 0; + u_int16_t power; data->length = sizeof(struct iw_range); memset(range, 0, sizeof(struct iw_range)); + power = ic->ic_max_txpower; + if (ic->ic_bsschan && (ic->ic_bsschan != IEEE80211_CHAN_ANYC)) + power = min(power, (u_int16_t) ic->ic_bsschan->ic_maxpower); + /* txpower (128 values, but will print out only IW_MAX_TXPOWER) */ - range->num_txpower = (ic->ic_txpowlimit >= 8) ? IW_MAX_TXPOWER : ic->ic_txpowlimit; - step = ic->ic_txpowlimit / (2 * (IW_MAX_TXPOWER - 1)); + power /= 2; /* Unit: 0.5 dBm */ + range->num_txpower = (power >= 8) ? IW_MAX_TXPOWER : power; + step = power / (IW_MAX_TXPOWER - 1); range->txpower[0] = 0; for (i = 1; i < IW_MAX_TXPOWER; i++) - range->txpower[i] = (ic->ic_txpowlimit/2) + range->txpower[i] = power - (IW_MAX_TXPOWER - i - 1) * step; range->txpower_capa = IW_TXPOW_DBM; @@ -1379,13 +1385,11 @@ ieee80211_ioctl_siwtxpow(struct net_devi int fixed, disabled; fixed = (ic->ic_flags & IEEE80211_F_TXPOW_FIXED); - disabled = (fixed && vap->iv_bss->ni_txpower == 0); + disabled = (fixed && ic->ic_txpowlimit == 0); if (rrq->disabled) { if (!disabled) { - if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) - return -EOPNOTSUPP; ic->ic_flags |= IEEE80211_F_TXPOW_FIXED; - vap->iv_bss->ni_txpower = 0; + ic->ic_txpowlimit = 0; goto done; } return 0; @@ -1396,30 +1400,12 @@ ieee80211_ioctl_siwtxpow(struct net_devi return -EOPNOTSUPP; if (rrq->flags != IW_TXPOW_DBM) return -EINVAL; - if (ic->ic_bsschan != IEEE80211_CHAN_ANYC) { - if ((ic->ic_bsschan->ic_maxregpower >= rrq->value) && - (ic->ic_txpowlimit/2 >= rrq->value)) { - vap->iv_bss->ni_txpower = 2 * rrq->value; - ic->ic_newtxpowlimit = 2 * rrq->value; - ic->ic_flags |= IEEE80211_F_TXPOW_FIXED; - } else - return -EINVAL; - } else { - /* - * No channel set yet - */ - if (ic->ic_txpowlimit/2 >= rrq->value) { - vap->iv_bss->ni_txpower = 2 * rrq->value; - ic->ic_newtxpowlimit = 2 * rrq->value; - ic->ic_flags |= IEEE80211_F_TXPOW_FIXED; - } - else - return -EINVAL; - } + ic->ic_txpowlimit = 2 * rrq->value; + ic->ic_flags |= IEEE80211_F_TXPOW_FIXED; } else { if (!fixed) /* no change */ return 0; - ic->ic_newtxpowlimit = IEEE80211_TXPOWER_MAX; + ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; ic->ic_flags &= ~IEEE80211_F_TXPOW_FIXED; } done: @@ -1588,9 +1574,23 @@ ieee80211_ioctl_giwtxpow(struct net_devi { struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; - - rrq->value = vap->iv_bss->ni_txpower / 2; - rrq->fixed = (ic->ic_flags & IEEE80211_F_TXPOW_FIXED) != 0; + unsigned int power = ic->ic_txpowlimit; + struct ieee80211_channel *c; + u_int16_t txp = ic->ic_max_txpower; + + if (ic->ic_bsschan && (ic->ic_bsschan != IEEE80211_CHAN_ANYC)) { + txp = min(txp, (u16) ic->ic_bsschan->ic_maxpower); + } + if (ic->ic_cur_txpower > 0) { + txp = min(txp, ic->ic_cur_txpower); + } + if (ic->ic_flags & IEEE80211_F_TXPOW_FIXED) { + txp = min(txp, ic->ic_txpowlimit); + rrq->fixed = 1; + } else { + rrq->fixed = 0; + } + rrq->value = txp / 2; rrq->disabled = (rrq->fixed && rrq->value == 0); rrq->flags = IW_TXPOW_DBM; return 0; --- a/ath/if_ath.c +++ b/ath/if_ath.c @@ -380,7 +380,6 @@ static unsigned int ath_dump_hal_map(str static u_int32_t ath_get_clamped_maxtxpower(struct ath_softc *sc); static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, u_int32_t new_clamped_maxtxpower); -static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc); static void ath_poll_disable(struct net_device *dev); static void ath_poll_enable(struct net_device *dev); @@ -3168,7 +3167,7 @@ ath_tx_startraw(struct net_device *dev, try0 = ph->try0; rt = sc->sc_currates; txrate = dot11_to_ratecode(sc, rt, ph->rate0); - power = ph->power > 60 ? 60 : ph->power; + power = ph->power > 63 ? 63 : ph->power; hdrlen = ieee80211_anyhdrsize(wh); pktlen = skb->len + IEEE80211_CRC_LEN; @@ -8394,7 +8393,7 @@ ath_tx_start(struct net_device *dev, str pktlen, /* packet length */ hdrlen, /* header length */ atype, /* Atheros packet type */ - MIN(ni->ni_txpower, 60), /* txpower */ + MIN(ni->ni_txpower, 63), /* txpower */ txrate, try0, /* series 0 rate/tries */ keyix, /* key cache index */ antenna, /* antenna mode */ @@ -10387,59 +10386,16 @@ ath_get_clamped_maxtxpower(struct ath_so /* XXX: this function needs some locking to avoid being called * twice/interrupted */ -/* 1. Save the currently specified maximum txpower (as clamped by madwifi) - * 2. Determine the real maximum txpower the card can support by - * setting a value that exceeds the maximum range (by one) and - * finding out what it limits us to. - * 3. Restore the saved maxtxpower value we had previously specified */ -static u_int32_t -ath_get_real_maxtxpower(struct ath_softc *sc) -{ - u_int32_t saved_clamped_maxtxpower; - u_int32_t real_maxtxpower; - - saved_clamped_maxtxpower = ath_get_clamped_maxtxpower(sc); - real_maxtxpower = - ath_set_clamped_maxtxpower(sc, IEEE80211_TXPOWER_MAX + 1); - ath_set_clamped_maxtxpower(sc, saved_clamped_maxtxpower); - return real_maxtxpower; -} - - -/* XXX: this function needs some locking to avoid being called - * twice/interrupted */ static void ath_update_txpow(struct ath_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = NULL; struct ath_hal *ah = sc->sc_ah; - u_int32_t prev_clamped_maxtxpower = 0; - u_int32_t new_clamped_maxtxpower = 0; /* Determine the previous value of maxtxpower */ - prev_clamped_maxtxpower = ath_get_clamped_maxtxpower(sc); - /* Determine the real maximum txpower the card can support */ - ic->ic_txpowlimit = ath_get_real_maxtxpower(sc); - /* Grab the new maxtxpower setting (which may have changed) */ - new_clamped_maxtxpower = ic->ic_newtxpowlimit; - /* Make sure the change is within limits, clamp it otherwise */ - if (ic->ic_newtxpowlimit > ic->ic_txpowlimit) - new_clamped_maxtxpower = ic->ic_txpowlimit; - /* Search for the VAP that needs a txpow change, if any */ - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - if (!tpc || ic->ic_newtxpowlimit != vap->iv_bss->ni_txpower) { - vap->iv_bss->ni_txpower = new_clamped_maxtxpower; - ieee80211_iterate_nodes(&vap->iv_ic->ic_sta, - set_node_txpower, - &new_clamped_maxtxpower); - } - } - - /* Store the assigned (clamped) maximum txpower and update the HAL */ - sc->sc_curtxpow = new_clamped_maxtxpower; - if (new_clamped_maxtxpower != prev_clamped_maxtxpower) - ath_hal_settxpowlimit(ah, new_clamped_maxtxpower); + ath_set_clamped_maxtxpower(sc, ic->ic_txpowlimit); + ic->ic_cur_txpower = ath_get_clamped_maxtxpower(sc); } #ifdef ATH_SUPERG_XR