Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 194980
b: refs/heads/master
c: 0aaffa9
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed May 7, 2010
1 parent 8066987 commit 7220c93
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 41 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f444de05d20e27cdd960c13fcbcfca3099f03143
refs/heads/master: 0aaffa9b9699894aab3266195a529baf9f96ac29
19 changes: 10 additions & 9 deletions trunk/drivers/net/wireless/mac80211_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,17 +651,17 @@ static void mac80211_hwsim_beacon(unsigned long arg)
add_timer(&data->beacon_timer);
}

static const char *hwsim_chantypes[] = {
[NL80211_CHAN_NO_HT] = "noht",
[NL80211_CHAN_HT20] = "ht20",
[NL80211_CHAN_HT40MINUS] = "ht40-",
[NL80211_CHAN_HT40PLUS] = "ht40+",
};

static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
{
struct mac80211_hwsim_data *data = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
static const char *chantypes[4] = {
[NL80211_CHAN_NO_HT] = "noht",
[NL80211_CHAN_HT20] = "ht20",
[NL80211_CHAN_HT40MINUS] = "ht40-",
[NL80211_CHAN_HT40PLUS] = "ht40+",
};
static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
[IEEE80211_SMPS_AUTOMATIC] = "auto",
[IEEE80211_SMPS_OFF] = "off",
Expand All @@ -672,7 +672,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
printk(KERN_DEBUG "%s:%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
wiphy_name(hw->wiphy), __func__,
conf->channel->center_freq,
chantypes[conf->channel_type],
hwsim_chantypes[conf->channel_type],
!!(conf->flags & IEEE80211_CONF_IDLE),
!!(conf->flags & IEEE80211_CONF_PS),
smps_modes[conf->smps_mode]);
Expand Down Expand Up @@ -760,9 +760,10 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
}

if (changed & BSS_CHANGED_HT) {
printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n",
printk(KERN_DEBUG " %s: HT: op_mode=0x%x, chantype=%s\n",
wiphy_name(hw->wiphy),
info->ht_operation_mode);
info->ht_operation_mode,
hwsim_chantypes[info->channel_type]);
}

if (changed & BSS_CHANGED_BASIC_RATES) {
Expand Down
4 changes: 4 additions & 0 deletions trunk/include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ enum ieee80211_bss_change {
* the current band.
* @bssid: The BSSID for this BSS
* @enable_beacon: whether beaconing should be enabled or not
* @channel_type: Channel type for this BSS -- the hardware might be
* configured for HT40+ while this BSS only uses no-HT, for
* example.
* @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info).
* This field is only valid when the channel type is one of the HT types.
* @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
Expand All @@ -215,6 +218,7 @@ struct ieee80211_bss_conf {
u16 ht_operation_mode;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
enum nl80211_channel_type channel_type;
};

/**
Expand Down
23 changes: 17 additions & 6 deletions trunk/net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1166,23 +1166,34 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
enum nl80211_channel_type channel_type)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = NULL;

if (netdev)
sdata = IEEE80211_DEV_TO_SUB_IF(netdev);

switch (ieee80211_get_channel_mode(local, NULL)) {
case CHAN_MODE_HOPPING:
return -EBUSY;
case CHAN_MODE_FIXED:
if (local->oper_channel == chan &&
local->oper_channel_type == channel_type)
if (local->oper_channel != chan)
return -EBUSY;
if (!sdata && local->_oper_channel_type == channel_type)
return 0;
return -EBUSY;
break;
case CHAN_MODE_UNDEFINED:
break;
}

local->oper_channel = chan;
local->oper_channel_type = channel_type;

return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
if (!ieee80211_set_channel_type(local, sdata, channel_type))
return -EBUSY;

ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);

return 0;
}

#ifdef CONFIG_PM
Expand Down Expand Up @@ -1406,7 +1417,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
* association, there's no need to send an action frame.
*/
if (!sdata->u.mgd.associated ||
sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
mutex_lock(&sdata->local->iflist_mtx);
ieee80211_recalc_smps(sdata->local, sdata);
mutex_unlock(&sdata->local->iflist_mtx);
Expand Down
70 changes: 70 additions & 0 deletions trunk/net/mac80211/chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* mac80211 - channel management
*/

#include <linux/nl80211.h>
#include "ieee80211_i.h"

enum ieee80211_chan_mode
Expand Down Expand Up @@ -55,3 +56,72 @@ ieee80211_get_channel_mode(struct ieee80211_local *local,

return mode;
}

bool ieee80211_set_channel_type(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type chantype)
{
struct ieee80211_sub_if_data *tmp;
enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
bool result;

mutex_lock(&local->iflist_mtx);

list_for_each_entry(tmp, &local->interfaces, list) {
if (tmp == sdata)
continue;

if (!ieee80211_sdata_running(tmp))
continue;

switch (tmp->vif.bss_conf.channel_type) {
case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
superchan = tmp->vif.bss_conf.channel_type;
break;
case NL80211_CHAN_HT40PLUS:
WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
superchan = NL80211_CHAN_HT40PLUS;
break;
case NL80211_CHAN_HT40MINUS:
WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
superchan = NL80211_CHAN_HT40MINUS;
break;
}
}

switch (superchan) {
case NL80211_CHAN_NO_HT:
case NL80211_CHAN_HT20:
/*
* allow any change that doesn't go to no-HT
* (if it already is no-HT no change is needed)
*/
if (chantype == NL80211_CHAN_NO_HT)
break;
superchan = chantype;
break;
case NL80211_CHAN_HT40PLUS:
case NL80211_CHAN_HT40MINUS:
/* allow smaller bandwidth and same */
if (chantype == NL80211_CHAN_NO_HT)
break;
if (chantype == NL80211_CHAN_HT20)
break;
if (superchan == chantype)
break;
result = false;
goto out;
}

local->_oper_channel_type = superchan;

if (sdata)
sdata->vif.bss_conf.channel_type = chantype;

result = true;
out:
mutex_unlock(&local->iflist_mtx);

return result;
}
5 changes: 3 additions & 2 deletions trunk/net/mac80211/ibss.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;

local->oper_channel = chan;
local->oper_channel_type = NL80211_CHAN_NO_HT;
WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);

sband = local->hw.wiphy->bands[chan->band];
Expand Down Expand Up @@ -910,7 +910,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
/* fix ourselves to that channel now already */
if (params->channel_fixed) {
sdata->local->oper_channel = params->channel;
sdata->local->oper_channel_type = NL80211_CHAN_NO_HT;
WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
NL80211_CHAN_NO_HT));
}

if (params->ie) {
Expand Down
5 changes: 4 additions & 1 deletion trunk/net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ struct ieee80211_local {
enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata;
enum nl80211_channel_type oper_channel_type;
enum nl80211_channel_type _oper_channel_type;
struct ieee80211_channel *oper_channel, *csa_channel;

/* Temporary remain-on-channel for off-channel operations */
Expand Down Expand Up @@ -1239,6 +1239,9 @@ enum ieee80211_chan_mode {
enum ieee80211_chan_mode
ieee80211_get_channel_mode(struct ieee80211_local *local,
struct ieee80211_sub_if_data *ignore);
bool ieee80211_set_channel_type(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
enum nl80211_channel_type chantype);

#ifdef CONFIG_MAC80211_NOINLINE
#define debug_noinline noinline
Expand Down
2 changes: 1 addition & 1 deletion trunk/net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
channel_type = local->tmp_channel_type;
} else {
chan = local->oper_channel;
channel_type = local->oper_channel_type;
channel_type = local->_oper_channel_type;
}

if (chan != local->hw.conf.channel ||
Expand Down
44 changes: 23 additions & 21 deletions trunk/net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta;
u32 changed = 0;
u16 ht_opmode;
bool enable_ht = true, ht_changed;
bool enable_ht = true;
enum nl80211_channel_type prev_chantype;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;

sband = local->hw.wiphy->bands[local->hw.conf.channel->band];

prev_chantype = sdata->vif.bss_conf.channel_type;

/* HT is not supported */
if (!sband->ht_cap.ht_supported)
enable_ht = false;
Expand Down Expand Up @@ -171,38 +174,37 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
}
}

ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
channel_type != local->hw.conf.channel_type;

if (local->tmp_channel)
local->tmp_channel_type = channel_type;
local->oper_channel_type = channel_type;

if (ht_changed) {
/* channel_type change automatically detected */
ieee80211_hw_config(local, 0);
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
/* can only fail due to HT40+/- mismatch */
channel_type = NL80211_CHAN_HT20;
WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
}

/* channel_type change automatically detected */
ieee80211_hw_config(local, 0);

if (prev_chantype != channel_type) {
rcu_read_lock();
sta = sta_info_get(sdata, bssid);
if (sta)
rate_control_rate_update(local, sband, sta,
IEEE80211_RC_HT_CHANGED,
local->oper_channel_type);
channel_type);
rcu_read_unlock();
}

/* disable HT */
if (!enable_ht)
return 0;
}

ht_opmode = le16_to_cpu(hti->operation_mode);

/* if bss configuration changed store the new one */
if (!sdata->ht_opmode_valid ||
sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
if (sdata->ht_opmode_valid != enable_ht ||
sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
prev_chantype != channel_type) {
changed |= BSS_CHANGED_HT;
sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
sdata->ht_opmode_valid = true;
sdata->ht_opmode_valid = enable_ht;
}

return changed;
Expand Down Expand Up @@ -865,7 +867,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_set_wmm_default(sdata);

/* channel(_type) changes are handled by ieee80211_hw_config */
local->oper_channel_type = NL80211_CHAN_NO_HT;
WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));

/* on the next assoc, re-program HT parameters */
sdata->ht_opmode_valid = false;
Expand All @@ -882,8 +884,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,

ieee80211_hw_config(local, config_changed);

/* And the BSSID changed -- not very interesting here */
changed |= BSS_CHANGED_BSSID;
/* The BSSID (not really interesting) and HT changed */
changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
ieee80211_bss_info_change_notify(sdata, changed);

if (remove_sta)
Expand Down Expand Up @@ -2265,7 +2267,7 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
if ((chan != local->tmp_channel ||
channel_type != local->tmp_channel_type) &&
(chan != local->oper_channel ||
channel_type != local->oper_channel_type))
channel_type != local->_oper_channel_type))
return -EBUSY;

skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
Expand Down

0 comments on commit 7220c93

Please sign in to comment.