summaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c132
1 files changed, 95 insertions, 37 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3c61060a4d2b..f9319a5dca64 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -693,6 +693,34 @@ void ieee80211_iterate_active_interfaces_rtnl(
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
+static void __iterate_stations(struct ieee80211_local *local,
+ void (*iterator)(void *data,
+ struct ieee80211_sta *sta),
+ void *data)
+{
+ struct sta_info *sta;
+
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (!sta->uploaded)
+ continue;
+
+ iterator(data, &sta->sta);
+ }
+}
+
+void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
+ void (*iterator)(void *data,
+ struct ieee80211_sta *sta),
+ void *data)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ rcu_read_lock();
+ __iterate_stations(local, iterator, data);
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic);
+
struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
@@ -1073,6 +1101,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
struct ieee80211_chanctx_conf *chanctx_conf;
int ac;
bool use_11b, enable_qos;
+ bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */
int aCWmin, aCWmax;
if (!local->ops->conf_tx)
@@ -1097,6 +1126,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
*/
enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
+ is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB);
+
/* Set defaults according to 802.11-2007 Table 7-37 */
aCWmax = 1023;
if (use_11b)
@@ -1118,7 +1149,10 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
- qparam.aifs = 7;
+ if (is_ocb)
+ qparam.aifs = 9;
+ else
+ qparam.aifs = 7;
break;
/* never happens but let's not leave undefined */
default:
@@ -1126,21 +1160,32 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
qparam.cw_max = aCWmax;
qparam.cw_min = aCWmin;
qparam.txop = 0;
- qparam.aifs = 3;
+ if (is_ocb)
+ qparam.aifs = 6;
+ else
+ qparam.aifs = 3;
break;
case IEEE80211_AC_VI:
qparam.cw_max = aCWmin;
qparam.cw_min = (aCWmin + 1) / 2 - 1;
- if (use_11b)
+ if (is_ocb)
+ qparam.txop = 0;
+ else if (use_11b)
qparam.txop = 6016/32;
else
qparam.txop = 3008/32;
- qparam.aifs = 2;
+
+ if (is_ocb)
+ qparam.aifs = 3;
+ else
+ qparam.aifs = 2;
break;
case IEEE80211_AC_VO:
qparam.cw_max = (aCWmin + 1) / 2 - 1;
qparam.cw_min = (aCWmin + 1) / 4 - 1;
- if (use_11b)
+ if (is_ocb)
+ qparam.txop = 0;
+ else if (use_11b)
qparam.txop = 3264/32;
else
qparam.txop = 1504/32;
@@ -1813,6 +1858,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
ieee80211_bss_info_change_notify(sdata, changed);
sdata_unlock(sdata);
break;
+ case NL80211_IFTYPE_OCB:
+ changed |= BSS_CHANGED_OCB;
+ ieee80211_bss_info_change_notify(sdata, changed);
+ break;
case NL80211_IFTYPE_ADHOC:
changed |= BSS_CHANGED_IBSS;
/* fall through */
@@ -1949,7 +1998,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
* We may want to change that later, however.
*/
if (!local->suspended || reconfig_due_to_wowlan)
- drv_restart_complete(local);
+ drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
if (!local->suspended)
return 0;
@@ -1960,6 +2009,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mb();
local->resuming = false;
+ if (!reconfig_due_to_wowlan)
+ drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND);
+
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
@@ -2052,42 +2104,36 @@ static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
return false;
}
-/**
- * ieee80211_ie_split - split an IE buffer according to ordering
- *
- * @ies: the IE buffer
- * @ielen: the length of the IE buffer
- * @ids: an array with element IDs that are allowed before
- * the split
- * @n_ids: the size of the element ID array
- * @offset: offset where to start splitting in the buffer
- *
- * This function splits an IE buffer by updating the @offset
- * variable to point to the location where the buffer should be
- * split.
- *
- * It assumes that the given IE buffer is well-formed, this
- * has to be guaranteed by the caller!
- *
- * It also assumes that the IEs in the buffer are ordered
- * correctly, if not the result of using this function will not
- * be ordered correctly either, i.e. it does no reordering.
- *
- * The function returns the offset where the next part of the
- * buffer starts, which may be @ielen if the entire (remainder)
- * of the buffer should be used.
- */
-size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
- const u8 *ids, int n_ids, size_t offset)
+size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
+ const u8 *ids, int n_ids,
+ const u8 *after_ric, int n_after_ric,
+ size_t offset)
{
size_t pos = offset;
- while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
- pos += 2 + ies[pos + 1];
+ while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) {
+ if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) {
+ pos += 2 + ies[pos + 1];
+
+ while (pos < ielen &&
+ !ieee80211_id_in_list(after_ric, n_after_ric,
+ ies[pos]))
+ pos += 2 + ies[pos + 1];
+ } else {
+ pos += 2 + ies[pos + 1];
+ }
+ }
return pos;
}
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+ const u8 *ids, int n_ids, size_t offset)
+{
+ return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset);
+}
+EXPORT_SYMBOL(ieee80211_ie_split);
+
size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
{
size_t pos = offset;
@@ -2526,11 +2572,23 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work)
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, radar_detected_work);
struct cfg80211_chan_def chandef = local->hw.conf.chandef;
+ struct ieee80211_chanctx *ctx;
+ int num_chanctx = 0;
+
+ mutex_lock(&local->chanctx_mtx);
+ list_for_each_entry(ctx, &local->chanctx_list, list) {
+ if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
+ continue;
+
+ num_chanctx++;
+ chandef = ctx->conf.def;
+ }
+ mutex_unlock(&local->chanctx_mtx);
ieee80211_dfs_cac_cancel(local);
- if (local->use_chanctx)
- /* currently not handled */
+ if (num_chanctx > 1)
+ /* XXX: multi-channel is not supported yet */
WARN_ON(1);
else
cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);