mac80211: refactor the parsing of chan switch ie

Refactor the channel switch IE parsing to reduce the number
of function parameters.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Chun-Yeow Yeoh 2013-10-14 19:08:29 -07:00 committed by Johannes Berg
parent 06be6b149f
commit c0f17eb9b2
4 changed files with 48 additions and 41 deletions

View File

@ -836,13 +836,13 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
bool beacon) bool beacon)
{ {
struct cfg80211_csa_settings params; struct cfg80211_csa_settings params;
struct ieee80211_csa_ie csa_ie;
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx; struct ieee80211_chanctx *chanctx;
enum nl80211_channel_type ch_type; enum nl80211_channel_type ch_type;
int err, num_chanctx; int err, num_chanctx;
u32 sta_flags; u32 sta_flags;
u8 mode;
if (sdata->vif.csa_active) if (sdata->vif.csa_active)
return true; return true;
@ -865,12 +865,10 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
} }
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
memset(&csa_ie, 0, sizeof(csa_ie));
err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
ifibss->chandef.chan->band, ifibss->chandef.chan->band,
sta_flags, ifibss->bssid, sta_flags, ifibss->bssid, &csa_ie);
&params.count, &mode,
&params.chandef);
/* can't switch to destination channel, fail */ /* can't switch to destination channel, fail */
if (err < 0) if (err < 0)
goto disconnect; goto disconnect;
@ -879,6 +877,9 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (err) if (err)
return false; return false;
params.count = csa_ie.count;
params.chandef = csa_ie.chandef;
if (ifibss->chandef.chan->band != params.chandef.chan->band) if (ifibss->chandef.chan->band != params.chandef.chan->band)
goto disconnect; goto disconnect;
@ -965,7 +966,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
"received channel switch announcement to go to channel %d MHz\n", "received channel switch announcement to go to channel %d MHz\n",
params.chandef.chan->center_freq); params.chandef.chan->center_freq);
params.block_tx = !!mode; params.block_tx = !!csa_ie.mode;
ieee80211_ibss_csa_beacon(sdata, &params); ieee80211_ibss_csa_beacon(sdata, &params);
sdata->csa_radar_required = params.radar_required; sdata->csa_radar_required = params.radar_required;

View File

@ -1208,6 +1208,14 @@ struct ieee80211_ra_tid {
u16 tid; u16 tid;
}; };
/* this struct holds the value parsing from channel switch IE */
struct ieee80211_csa_ie {
struct cfg80211_chan_def chandef;
u8 mode;
u8 count;
u8 ttl;
};
/* Parsed Information Elements */ /* Parsed Information Elements */
struct ieee802_11_elems { struct ieee802_11_elems {
const u8 *ie_start; const u8 *ie_start;
@ -1505,17 +1513,16 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
* %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT, * %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT,
* %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ, * %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ,
* %IEEE80211_STA_DISABLE_160MHZ. * %IEEE80211_STA_DISABLE_160MHZ.
* @count: to be filled with the counter until the switch (on success only)
* @bssid: the currently connected bssid (for reporting) * @bssid: the currently connected bssid (for reporting)
* @mode: to be filled with CSA mode (on success only) * @csa_ie: parsed 802.11 csa elements on count, mode, chandef and mesh ttl.
* @new_chandef: to be filled with destination chandef (on success only) All of them will be filled with if success only.
* Return: 0 on success, <0 on error and >0 if there is nothing to parse. * Return: 0 on success, <0 on error and >0 if there is nothing to parse.
*/ */
int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems, bool beacon, struct ieee802_11_elems *elems, bool beacon,
enum ieee80211_band current_band, enum ieee80211_band current_band,
u32 sta_flags, u8 *bssid, u8 *count, u8 *mode, u32 sta_flags, u8 *bssid,
struct cfg80211_chan_def *new_chandef); struct ieee80211_csa_ie *csa_ie);
/* Suspend/resume and hw reconfiguration */ /* Suspend/resume and hw reconfiguration */
int ieee80211_reconfig(struct ieee80211_local *local); int ieee80211_reconfig(struct ieee80211_local *local);

View File

@ -958,9 +958,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct cfg80211_bss *cbss = ifmgd->associated; struct cfg80211_bss *cbss = ifmgd->associated;
struct ieee80211_chanctx *chanctx; struct ieee80211_chanctx *chanctx;
enum ieee80211_band current_band; enum ieee80211_band current_band;
u8 count; struct ieee80211_csa_ie csa_ie;
u8 mode;
struct cfg80211_chan_def new_chandef = {};
int res; int res;
sdata_assert_lock(sdata); sdata_assert_lock(sdata);
@ -976,24 +974,24 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return; return;
current_band = cbss->channel->band; current_band = cbss->channel->band;
memset(&csa_ie, 0, sizeof(csa_ie));
res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band, res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,
ifmgd->flags, ifmgd->flags,
ifmgd->associated->bssid, &count, ifmgd->associated->bssid, &csa_ie);
&mode, &new_chandef);
if (res < 0) if (res < 0)
ieee80211_queue_work(&local->hw, ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work); &ifmgd->csa_connection_drop_work);
if (res) if (res)
return; return;
if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef, if (!cfg80211_chandef_usable(local->hw.wiphy, &csa_ie.chandef,
IEEE80211_CHAN_DISABLED)) { IEEE80211_CHAN_DISABLED)) {
sdata_info(sdata, sdata_info(sdata,
"AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
ifmgd->associated->bssid, ifmgd->associated->bssid,
new_chandef.chan->center_freq, csa_ie.chandef.chan->center_freq,
new_chandef.width, new_chandef.center_freq1, csa_ie.chandef.width, csa_ie.chandef.center_freq1,
new_chandef.center_freq2); csa_ie.chandef.center_freq2);
ieee80211_queue_work(&local->hw, ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work); &ifmgd->csa_connection_drop_work);
return; return;
@ -1037,9 +1035,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
} }
mutex_unlock(&local->chanctx_mtx); mutex_unlock(&local->chanctx_mtx);
local->csa_chandef = new_chandef; local->csa_chandef = csa_ie.chandef;
if (mode) if (csa_ie.mode)
ieee80211_stop_queues_by_reason(&local->hw, ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_MAX_QUEUE_MAP, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA); IEEE80211_QUEUE_STOP_REASON_CSA);
@ -1048,9 +1046,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
/* use driver's channel switch callback */ /* use driver's channel switch callback */
struct ieee80211_channel_switch ch_switch = { struct ieee80211_channel_switch ch_switch = {
.timestamp = timestamp, .timestamp = timestamp,
.block_tx = mode, .block_tx = csa_ie.mode,
.chandef = new_chandef, .chandef = csa_ie.chandef,
.count = count, .count = csa_ie.count,
}; };
drv_channel_switch(local, &ch_switch); drv_channel_switch(local, &ch_switch);
@ -1058,11 +1056,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
} }
/* channel switch handled in software */ /* channel switch handled in software */
if (count <= 1) if (csa_ie.count <= 1)
ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work); ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work);
else else
mod_timer(&ifmgd->chswitch_timer, mod_timer(&ifmgd->chswitch_timer,
TU_TO_EXP_TIME(count * cbss->beacon_interval)); TU_TO_EXP_TIME(csa_ie.count * cbss->beacon_interval));
} }
static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
@ -3994,7 +3992,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
} }
/* prepare assoc data */ /* prepare assoc data */
ifmgd->beacon_crc_valid = false; ifmgd->beacon_crc_valid = false;
/* /*

View File

@ -24,8 +24,8 @@
int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems, bool beacon, struct ieee802_11_elems *elems, bool beacon,
enum ieee80211_band current_band, enum ieee80211_band current_band,
u32 sta_flags, u8 *bssid, u8 *count, u8 *mode, u32 sta_flags, u8 *bssid,
struct cfg80211_chan_def *new_chandef) struct ieee80211_csa_ie *csa_ie)
{ {
enum ieee80211_band new_band; enum ieee80211_band new_band;
int new_freq; int new_freq;
@ -62,13 +62,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
return -EINVAL; return -EINVAL;
} }
new_chan_no = elems->ext_chansw_ie->new_ch_num; new_chan_no = elems->ext_chansw_ie->new_ch_num;
*count = elems->ext_chansw_ie->count; csa_ie->count = elems->ext_chansw_ie->count;
*mode = elems->ext_chansw_ie->mode; csa_ie->mode = elems->ext_chansw_ie->mode;
} else if (elems->ch_switch_ie) { } else if (elems->ch_switch_ie) {
new_band = current_band; new_band = current_band;
new_chan_no = elems->ch_switch_ie->new_ch_num; new_chan_no = elems->ch_switch_ie->new_ch_num;
*count = elems->ch_switch_ie->count; csa_ie->count = elems->ch_switch_ie->count;
*mode = elems->ch_switch_ie->mode; csa_ie->mode = elems->ch_switch_ie->mode;
} else { } else {
/* nothing here we understand */ /* nothing here we understand */
return 1; return 1;
@ -103,25 +103,26 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
default: default:
/* secondary_channel_offset was present but is invalid */ /* secondary_channel_offset was present but is invalid */
case IEEE80211_HT_PARAM_CHA_SEC_NONE: case IEEE80211_HT_PARAM_CHA_SEC_NONE:
cfg80211_chandef_create(new_chandef, new_chan, cfg80211_chandef_create(&csa_ie->chandef, new_chan,
NL80211_CHAN_HT20); NL80211_CHAN_HT20);
break; break;
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
cfg80211_chandef_create(new_chandef, new_chan, cfg80211_chandef_create(&csa_ie->chandef, new_chan,
NL80211_CHAN_HT40PLUS); NL80211_CHAN_HT40PLUS);
break; break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW: case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
cfg80211_chandef_create(new_chandef, new_chan, cfg80211_chandef_create(&csa_ie->chandef, new_chan,
NL80211_CHAN_HT40MINUS); NL80211_CHAN_HT40MINUS);
break; break;
case -1: case -1:
cfg80211_chandef_create(new_chandef, new_chan, cfg80211_chandef_create(&csa_ie->chandef, new_chan,
NL80211_CHAN_NO_HT); NL80211_CHAN_NO_HT);
/* keep width for 5/10 MHz channels */ /* keep width for 5/10 MHz channels */
switch (sdata->vif.bss_conf.chandef.width) { switch (sdata->vif.bss_conf.chandef.width) {
case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10: case NL80211_CHAN_WIDTH_10:
new_chandef->width = sdata->vif.bss_conf.chandef.width; csa_ie->chandef.width =
sdata->vif.bss_conf.chandef.width;
break; break;
default: default:
break; break;
@ -171,13 +172,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
/* if VHT data is there validate & use it */ /* if VHT data is there validate & use it */
if (new_vht_chandef.chan) { if (new_vht_chandef.chan) {
if (!cfg80211_chandef_compatible(&new_vht_chandef, if (!cfg80211_chandef_compatible(&new_vht_chandef,
new_chandef)) { &csa_ie->chandef)) {
sdata_info(sdata, sdata_info(sdata,
"BSS %pM: CSA has inconsistent channel data, disconnecting\n", "BSS %pM: CSA has inconsistent channel data, disconnecting\n",
bssid); bssid);
return -EINVAL; return -EINVAL;
} }
*new_chandef = new_vht_chandef; csa_ie->chandef = new_vht_chandef;
} }
return 0; return 0;