]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/mac80211/cfg.c
cfg80211: Convert del_station() callback to use a param struct
[karo-tx-linux.git] / net / mac80211 / cfg.c
index 4d8989b8796067898b3318b08576b32bb6a4d346..a1498416ad557d006d94c1fa96f7092d0b8212c9 100644 (file)
@@ -2,6 +2,7 @@
  * mac80211 configuration hooks for cfg80211
  *
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2013-2014  Intel Mobile Communications GmbH
  *
  * This file is GPLv2 as found in COPYING.
  */
@@ -682,8 +683,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        if (old)
                return -EALREADY;
 
-       /* TODO: make hostapd tell us what it wants */
-       sdata->smps_mode = IEEE80211_SMPS_OFF;
+       switch (params->smps_mode) {
+       case NL80211_SMPS_OFF:
+               sdata->smps_mode = IEEE80211_SMPS_OFF;
+               break;
+       case NL80211_SMPS_STATIC:
+               sdata->smps_mode = IEEE80211_SMPS_STATIC;
+               break;
+       case NL80211_SMPS_DYNAMIC:
+               sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
+               break;
+       default:
+               return -EINVAL;
+       }
        sdata->needed_rx_chains = sdata->local->rx_chains;
 
        mutex_lock(&local->mtx);
@@ -1213,14 +1225,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-                                const u8 *mac)
+                                struct station_del_parameters *params)
 {
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (mac)
-               return sta_info_destroy_addr_bss(sdata, mac);
+       if (params->mac)
+               return sta_info_destroy_addr_bss(sdata, params->mac);
 
        sta_info_flush(sdata);
        return 0;
@@ -1504,6 +1516,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
+                         struct mpath_info *pinfo)
+{
+       memset(pinfo, 0, sizeof(*pinfo));
+       memcpy(mpp, mpath->mpp, ETH_ALEN);
+
+       pinfo->generation = mpp_paths_generation;
+}
+
+static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
+                            u8 *dst, u8 *mpp, struct mpath_info *pinfo)
+
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct mesh_path *mpath;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       rcu_read_lock();
+       mpath = mpp_path_lookup(sdata, dst);
+       if (!mpath) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+       memcpy(dst, mpath->dst, ETH_ALEN);
+       mpp_set_pinfo(mpath, mpp, pinfo);
+       rcu_read_unlock();
+       return 0;
+}
+
+static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
+                             int idx, u8 *dst, u8 *mpp,
+                             struct mpath_info *pinfo)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct mesh_path *mpath;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       rcu_read_lock();
+       mpath = mpp_path_lookup_by_idx(sdata, idx);
+       if (!mpath) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+       memcpy(dst, mpath->dst, ETH_ALEN);
+       mpp_set_pinfo(mpath, mpp, pinfo);
+       rcu_read_unlock();
+       return 0;
+}
+
 static int ieee80211_get_mesh_config(struct wiphy *wiphy,
                                struct net_device *dev,
                                struct mesh_config *conf)
@@ -1977,8 +2040,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
                        return err;
        }
 
-       if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
-               err = drv_set_coverage_class(local, wiphy->coverage_class);
+       if ((changed & WIPHY_PARAM_COVERAGE_CLASS) ||
+           (changed & WIPHY_PARAM_DYN_ACK)) {
+               s16 coverage_class;
+
+               coverage_class = changed & WIPHY_PARAM_COVERAGE_CLASS ?
+                                       wiphy->coverage_class : -1;
+               err = drv_set_coverage_class(local, coverage_class);
 
                if (err)
                        return err;
@@ -2351,6 +2419,58 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
        return 0;
 }
 
+static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local,
+                                          struct ieee80211_roc_work *new_roc,
+                                          struct ieee80211_roc_work *cur_roc)
+{
+       unsigned long j = jiffies;
+       unsigned long cur_roc_end = cur_roc->hw_start_time +
+                                   msecs_to_jiffies(cur_roc->duration);
+       struct ieee80211_roc_work *next_roc;
+       int new_dur;
+
+       if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun))
+               return false;
+
+       if (time_after(j + IEEE80211_ROC_MIN_LEFT, cur_roc_end))
+               return false;
+
+       ieee80211_handle_roc_started(new_roc);
+
+       new_dur = new_roc->duration - jiffies_to_msecs(cur_roc_end - j);
+
+       /* cur_roc is long enough - add new_roc to the dependents list. */
+       if (new_dur <= 0) {
+               list_add_tail(&new_roc->list, &cur_roc->dependents);
+               return true;
+       }
+
+       new_roc->duration = new_dur;
+
+       /*
+        * if cur_roc was already coalesced before, we might
+        * want to extend the next roc instead of adding
+        * a new one.
+        */
+       next_roc = list_entry(cur_roc->list.next,
+                             struct ieee80211_roc_work, list);
+       if (&next_roc->list != &local->roc_list &&
+           next_roc->chan == new_roc->chan &&
+           next_roc->sdata == new_roc->sdata &&
+           !WARN_ON(next_roc->started)) {
+               list_add_tail(&new_roc->list, &next_roc->dependents);
+               next_roc->duration = max(next_roc->duration,
+                                        new_roc->duration);
+               next_roc->type = max(next_roc->type, new_roc->type);
+               return true;
+       }
+
+       /* add right after cur_roc */
+       list_add(&new_roc->list, &cur_roc->list);
+
+       return true;
+}
+
 static int ieee80211_start_roc_work(struct ieee80211_local *local,
                                    struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_channel *channel,
@@ -2456,8 +2576,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 
                /* If it has already started, it's more difficult ... */
                if (local->ops->remain_on_channel) {
-                       unsigned long j = jiffies;
-
                        /*
                         * In the offloaded ROC case, if it hasn't begun, add
                         * this new one to the dependent list to be handled
@@ -2480,28 +2598,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                                break;
                        }
 
-                       if (time_before(j + IEEE80211_ROC_MIN_LEFT,
-                                       tmp->hw_start_time +
-                                       msecs_to_jiffies(tmp->duration))) {
-                               int new_dur;
-
-                               ieee80211_handle_roc_started(roc);
-
-                               new_dur = roc->duration -
-                                         jiffies_to_msecs(tmp->hw_start_time +
-                                                          msecs_to_jiffies(
-                                                               tmp->duration) -
-                                                          j);
-
-                               if (new_dur > 0) {
-                                       /* add right after tmp */
-                                       list_add(&roc->list, &tmp->list);
-                               } else {
-                                       list_add_tail(&roc->list,
-                                                     &tmp->dependents);
-                               }
+                       if (ieee80211_coalesce_started_roc(local, roc, tmp))
                                queued = true;
-                       }
                } else if (del_timer_sync(&tmp->work.timer)) {
                        unsigned long new_end;
 
@@ -2803,11 +2901,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                if (sdata->reserved_ready)
                        return 0;
 
-               err = ieee80211_vif_use_reserved_context(sdata);
-               if (err)
-                       return err;
-
-               return 0;
+               return ieee80211_vif_use_reserved_context(sdata);
        }
 
        if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
@@ -2821,7 +2915,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                return err;
 
        ieee80211_bss_info_change_notify(sdata, changed);
-       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
@@ -2829,6 +2922,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                sdata->csa_block_tx = false;
        }
 
+       err = drv_post_channel_switch(sdata);
+       if (err)
+               return err;
+
+       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+
        return 0;
 }
 
@@ -3006,6 +3105,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_channel_switch ch_switch;
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *chanctx;
        int err, changed = 0;
@@ -3041,6 +3141,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       err = drv_pre_channel_switch(sdata, &ch_switch);
+       if (err)
+               goto out;
+
        err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
                                            chanctx->mode,
                                            params->radar_required);
@@ -3054,6 +3158,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       ch_switch.timestamp = 0;
+       ch_switch.device_timestamp = 0;
+       ch_switch.block_tx = params->block_tx;
+       ch_switch.chandef = params->chandef;
+       ch_switch.count = params->count;
+
        err = ieee80211_set_csa_beacon(sdata, params, &changed);
        if (err) {
                ieee80211_vif_unreserve_chanctx(sdata);
@@ -3500,6 +3610,8 @@ const struct cfg80211_ops mac80211_config_ops = {
        .change_mpath = ieee80211_change_mpath,
        .get_mpath = ieee80211_get_mpath,
        .dump_mpath = ieee80211_dump_mpath,
+       .get_mpp = ieee80211_get_mpp,
+       .dump_mpp = ieee80211_dump_mpp,
        .update_mesh_config = ieee80211_update_mesh_config,
        .get_mesh_config = ieee80211_get_mesh_config,
        .join_mesh = ieee80211_join_mesh,