ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
}
-void
+static void
ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
- const struct ieee80211_channel_sw_ie *sw_elem,
- struct ieee80211_bss *bss, u64 timestamp)
+ u64 timestamp, struct ieee802_11_elems *elems)
{
- struct cfg80211_bss *cbss =
- container_of((void *)bss, struct cfg80211_bss, priv);
- struct ieee80211_channel *new_ch;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num,
- cbss->channel->band);
+ struct cfg80211_bss *cbss = ifmgd->associated;
+ struct ieee80211_bss *bss;
+ struct ieee80211_channel *new_ch;
+ int new_freq;
struct ieee80211_chanctx *chanctx;
ASSERT_MGD_MTX(ifmgd);
- if (!ifmgd->associated)
+ if (!cbss)
return;
if (sdata->local->scanning)
return;
- /* Disregard subsequent beacons if we are already running a timer
- processing a CSA */
-
+ /* disregard subsequent announcements if we are already processing */
if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
return;
+ if (!elems->ch_switch_ie)
+ return;
+
+ bss = (void *)cbss->priv;
+
+ new_freq = ieee80211_channel_to_frequency(
+ elems->ch_switch_ie->new_ch_num,
+ cbss->channel->band);
new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
sdata_info(sdata,
sdata->local->csa_channel = new_ch;
- if (sw_elem->mode)
+ if (elems->ch_switch_ie->mode)
ieee80211_stop_queues_by_reason(&sdata->local->hw,
IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
/* use driver's channel switch callback */
struct ieee80211_channel_switch ch_switch = {
.timestamp = timestamp,
- .block_tx = sw_elem->mode,
+ .block_tx = elems->ch_switch_ie->mode,
.channel = new_ch,
- .count = sw_elem->count,
+ .count = elems->ch_switch_ie->count,
};
drv_channel_switch(sdata->local, &ch_switch);
}
/* channel switch handled in software */
- if (sw_elem->count <= 1)
+ if (elems->ch_switch_ie->count <= 1)
ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
else
mod_timer(&ifmgd->chswitch_timer,
- TU_TO_EXP_TIME(sw_elem->count *
+ TU_TO_EXP_TIME(elems->ch_switch_ie->count *
cbss->beacon_interval));
}
if (bss)
ieee80211_rx_bss_put(local, bss);
- if (!sdata->u.mgd.associated)
+ if (!sdata->u.mgd.associated ||
+ !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid))
return;
if (need_ps) {
mutex_unlock(&local->iflist_mtx);
}
- if (elems->ch_switch_ie &&
- memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0)
- ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie,
- bss, rx_status->mactime);
+ ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems);
}
rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss);
break;
case IEEE80211_STYPE_ACTION:
- switch (mgmt->u.action.category) {
- case WLAN_CATEGORY_SPECTRUM_MGMT:
+ if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
+ struct ieee802_11_elems elems;
+ int ies_len = skb->len -
+ offsetof(struct ieee80211_mgmt,
+ u.action.u.chan_switch.variable);
+
+ if (ies_len < 0)
+ break;
+
+ ieee802_11_parse_elems(
+ mgmt->u.action.u.chan_switch.variable,
+ ies_len, &elems);
+
+ if (elems.parse_error)
+ break;
+
ieee80211_sta_process_chanswitch(sdata,
- &mgmt->u.action.u.chan_switch.sw_elem,
- (void *)ifmgd->associated->priv,
- rx_status->mactime);
- break;
+ rx_status->mactime,
+ &elems);
}
+ break;
}
mutex_unlock(&ifmgd->mtx);