diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 87 |
1 files changed, 64 insertions, 23 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2e7855a1b10..b455e7264f4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2865,30 +2865,38 @@ void ieee80211_csa_finalize_work(struct work_struct *work) if (!ieee80211_sdata_running(sdata)) return; - if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP)) - return; - sdata->radar_required = sdata->csa_radar_required; err = ieee80211_vif_change_channel(sdata, &local->csa_chandef, &changed); if (WARN_ON(err < 0)) return; - err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); - if (err < 0) - return; + ieee80211_bss_info_change_notify(sdata, changed); - changed |= err; - kfree(sdata->u.ap.next_beacon); - sdata->u.ap.next_beacon = NULL; + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon); + if (err < 0) + return; + changed |= err; + kfree(sdata->u.ap.next_beacon); + sdata->u.ap.next_beacon = NULL; + + ieee80211_bss_info_change_notify(sdata, err); + break; + case NL80211_IFTYPE_ADHOC: + ieee80211_ibss_finish_csa(sdata); + break; + default: + WARN_ON(1); + return; + } sdata->vif.csa_active = false; ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_CSA); - ieee80211_bss_info_change_notify(sdata, changed); - cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef); } @@ -2936,20 +2944,56 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, if (sdata->vif.csa_active) return -EBUSY; - /* only handle AP for now. */ switch (sdata->vif.type) { case NL80211_IFTYPE_AP: + sdata->csa_counter_offset_beacon = + params->counter_offset_beacon; + sdata->csa_counter_offset_presp = params->counter_offset_presp; + sdata->u.ap.next_beacon = + cfg80211_beacon_dup(¶ms->beacon_after); + if (!sdata->u.ap.next_beacon) + return -ENOMEM; + + err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); + if (err < 0) { + kfree(sdata->u.ap.next_beacon); + return err; + } + break; + case NL80211_IFTYPE_ADHOC: + if (!sdata->vif.bss_conf.ibss_joined) + return -EINVAL; + + if (params->chandef.width != sdata->u.ibss.chandef.width) + return -EINVAL; + + switch (params->chandef.width) { + case NL80211_CHAN_WIDTH_40: + if (cfg80211_get_chandef_type(¶ms->chandef) != + cfg80211_get_chandef_type(&sdata->u.ibss.chandef)) + return -EINVAL; + case NL80211_CHAN_WIDTH_5: + case NL80211_CHAN_WIDTH_10: + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + break; + default: + return -EINVAL; + } + + /* changes into another band are not supported */ + if (sdata->u.ibss.chandef.chan->band != + params->chandef.chan->band) + return -EINVAL; + + err = ieee80211_ibss_csa_beacon(sdata, params); + if (err < 0) + return err; break; default: return -EOPNOTSUPP; } - sdata->u.ap.next_beacon = cfg80211_beacon_dup(¶ms->beacon_after); - if (!sdata->u.ap.next_beacon) - return -ENOMEM; - - sdata->csa_counter_offset_beacon = params->counter_offset_beacon; - sdata->csa_counter_offset_presp = params->counter_offset_presp; sdata->csa_radar_required = params->radar_required; if (params->block_tx) @@ -2957,10 +3001,6 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, IEEE80211_MAX_QUEUE_MAP, IEEE80211_QUEUE_STOP_REASON_CSA); - err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa); - if (err < 0) - return err; - local->csa_chandef = params->chandef; sdata->vif.csa_active = true; @@ -3014,7 +3054,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, need_offchan = true; if (!ieee80211_is_action(mgmt->frame_control) || mgmt->u.action.category == WLAN_CATEGORY_PUBLIC || - mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED) + mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED || + mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) break; rcu_read_lock(); sta = sta_info_get(sdata, mgmt->da); |