Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / net / mac80211 / cfg.c
index 9ae1a47..facf233 100644 (file)
@@ -78,17 +78,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                                  enum nl80211_iftype type, u32 *flags,
                                  struct vif_params *params)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        int ret;
 
-       if (netif_running(dev))
+       if (ieee80211_sdata_running(sdata))
                return -EBUSY;
 
        if (!nl80211_params_check(type, params))
                return -EINVAL;
 
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
        ret = ieee80211_if_change_type(sdata, type);
        if (ret)
                return ret;
@@ -150,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        rcu_read_lock();
 
        if (mac_addr) {
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get_bss(sdata, mac_addr);
                if (!sta) {
                        ieee80211_key_free(key);
                        err = -ENOENT;
@@ -181,7 +179,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
        if (mac_addr) {
                ret = -ENOENT;
 
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get_bss(sdata, mac_addr);
                if (!sta)
                        goto out_unlock;
 
@@ -228,7 +226,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        rcu_read_lock();
 
        if (mac_addr) {
-               sta = sta_info_get(sdata->local, mac_addr);
+               sta = sta_info_get_bss(sdata, mac_addr);
                if (!sta)
                        goto out;
 
@@ -415,15 +413,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_info *sinfo)
 {
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sta_info *sta;
        int ret = -ENOENT;
 
        rcu_read_lock();
 
-       /* XXX: verify sta->dev == dev */
-
-       sta = sta_info_get(local, mac);
+       sta = sta_info_get_bss(sdata, mac);
        if (sta) {
                ret = 0;
                sta_set_sinfo(sta, sinfo);
@@ -732,7 +728,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        } else
                sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (compare_ether_addr(mac, dev->dev_addr) == 0)
+       if (compare_ether_addr(mac, sdata->vif.addr) == 0)
                return -EINVAL;
 
        if (is_multicast_ether_addr(mac))
@@ -779,8 +775,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
        if (mac) {
                rcu_read_lock();
 
-               /* XXX: get sta belonging to dev */
-               sta = sta_info_get(local, mac);
+               sta = sta_info_get_bss(sdata, mac);
                if (!sta) {
                        rcu_read_unlock();
                        return -ENOENT;
@@ -801,14 +796,14 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                                    u8 *mac,
                                    struct station_parameters *params)
 {
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *vlansdata;
 
        rcu_read_lock();
 
-       /* XXX: get sta belonging to dev */
-       sta = sta_info_get(local, mac);
+       sta = sta_info_get_bss(sdata, mac);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -847,7 +842,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *dst, u8 *next_hop)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
        struct sta_info *sta;
@@ -856,7 +850,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        rcu_read_lock();
-       sta = sta_info_get(local, next_hop);
+       sta = sta_info_get(sdata, next_hop);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -895,7 +889,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
                                    struct net_device *dev,
                                    u8 *dst, u8 *next_hop)
 {
-       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        struct mesh_path *mpath;
        struct sta_info *sta;
@@ -904,7 +897,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, next_hop);
+       sta = sta_info_get(sdata, next_hop);
        if (!sta) {
                rcu_read_unlock();
                return -ENOENT;
@@ -1092,6 +1085,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
                        params->use_short_preamble;
                changed |= BSS_CHANGED_ERP_PREAMBLE;
        }
+
+       if (!sdata->vif.bss_conf.use_short_slot &&
+           sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) {
+               sdata->vif.bss_conf.use_short_slot = true;
+               changed |= BSS_CHANGED_ERP_SLOT;
+       }
+
        if (params->use_short_slot_time >= 0) {
                sdata->vif.bss_conf.use_short_slot =
                        params->use_short_slot_time;
@@ -1135,6 +1135,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        p.cw_max = params->cwmax;
        p.cw_min = params->cwmin;
        p.txop = params->txop;
+
+       /*
+        * Setting tx queue params disables u-apsd because it's only
+        * called in master mode.
+        */
+       p.uapsd = false;
+
        if (drv_conf_tx(local, params->queue, &p)) {
                printk(KERN_DEBUG "%s: failed to set TX queue "
                       "parameters for queue %d\n",
@@ -1237,6 +1244,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
        struct ieee80211_local *local = wiphy_priv(wiphy);
        int err;
 
+       if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
+               err = drv_set_coverage_class(local, wiphy->coverage_class);
+
+               if (err)
+                       return err;
+       }
+
        if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
                err = drv_set_rts_threshold(local, wiphy->rts_threshold);
 
@@ -1324,6 +1338,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
 }
 #endif
 
+int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
+                            enum ieee80211_smps_mode smps_mode)
+{
+       const u8 *ap;
+       enum ieee80211_smps_mode old_req;
+       int err;
+
+       old_req = sdata->u.mgd.req_smps;
+       sdata->u.mgd.req_smps = smps_mode;
+
+       if (old_req == smps_mode &&
+           smps_mode != IEEE80211_SMPS_AUTOMATIC)
+               return 0;
+
+       /*
+        * If not associated, or current association is not an HT
+        * association, there's no need to send an action frame.
+        */
+       if (!sdata->u.mgd.associated ||
+           sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
+               mutex_lock(&sdata->local->iflist_mtx);
+               ieee80211_recalc_smps(sdata->local, sdata);
+               mutex_unlock(&sdata->local->iflist_mtx);
+               return 0;
+       }
+
+       ap = sdata->u.mgd.associated->bssid;
+
+       if (smps_mode == IEEE80211_SMPS_AUTOMATIC) {
+               if (sdata->u.mgd.powersave)
+                       smps_mode = IEEE80211_SMPS_DYNAMIC;
+               else
+                       smps_mode = IEEE80211_SMPS_OFF;
+       }
+
+       /* send SM PS frame to AP */
+       err = ieee80211_send_smps_action(sdata, smps_mode,
+                                        ap, ap);
+       if (err)
+               sdata->u.mgd.req_smps = old_req;
+
+       return err;
+}
+
 static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
                                    bool enabled, int timeout)
 {
@@ -1344,6 +1402,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        sdata->u.mgd.powersave = enabled;
        conf->dynamic_ps_timeout = timeout;
 
+       /* no change, but if automatic follow powersave */
+       mutex_lock(&sdata->u.mgd.mtx);
+       __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
+       mutex_unlock(&sdata->u.mgd.mtx);
+
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 
@@ -1359,39 +1422,43 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       int i, err = -EINVAL;
-       u32 target_rate;
-       struct ieee80211_supported_band *sband;
+       int i;
 
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       /*
+        * This _could_ be supported by providing a hook for
+        * drivers for this function, but at this point it
+        * doesn't seem worth bothering.
+        */
+       if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+               return -EOPNOTSUPP;
 
-       /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
-        * target_rate = X, rate->fixed = 1 means only rate X
-        * target_rate = X, rate->fixed = 0 means all rates <= X */
-       sdata->max_ratectrl_rateidx = -1;
-       sdata->force_unicast_rateidx = -1;
 
-       if (mask->fixed)
-               target_rate = mask->fixed / 100;
-       else if (mask->maxrate)
-               target_rate = mask->maxrate / 100;
-       else
-               return 0;
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+               sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
 
-       for (i=0; i< sband->n_bitrates; i++) {
-               struct ieee80211_rate *brate = &sband->bitrates[i];
-               int this_rate = brate->bitrate;
+       return 0;
+}
 
-               if (target_rate == this_rate) {
-                       sdata->max_ratectrl_rateidx = i;
-                       if (mask->fixed)
-                               sdata->force_unicast_rateidx = i;
-                       err = 0;
-                       break;
-               }
-       }
+static int ieee80211_remain_on_channel(struct wiphy *wiphy,
+                                      struct net_device *dev,
+                                      struct ieee80211_channel *chan,
+                                      enum nl80211_channel_type channel_type,
+                                      unsigned int duration,
+                                      u64 *cookie)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       return err;
+       return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
+                                             duration, cookie);
+}
+
+static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
+                                             struct net_device *dev,
+                                             u64 cookie)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
 }
 
 struct cfg80211_ops mac80211_config_ops = {
@@ -1440,4 +1507,6 @@ struct cfg80211_ops mac80211_config_ops = {
        CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
        .set_power_mgmt = ieee80211_set_power_mgmt,
        .set_bitrate_mask = ieee80211_set_bitrate_mask,
+       .remain_on_channel = ieee80211_remain_on_channel,
+       .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
 };