diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 142 |
1 files changed, 108 insertions, 34 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6dc3579c0ac..2e5e841e9b7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -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(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(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(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(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(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(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; @@ -1324,6 +1317,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) { @@ -1341,6 +1378,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); @@ -1356,15 +1398,25 @@ 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; + int i; u32 target_rate; struct ieee80211_supported_band *sband; + /* + * 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; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates + /* + * 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 */ + * target_rate = X, rate->fixed = 0 means all rates <= X + */ sdata->max_ratectrl_rateidx = -1; sdata->force_unicast_rateidx = -1; @@ -1375,20 +1427,40 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, else return 0; - for (i=0; i< sband->n_bitrates; i++) { - struct ieee80211_rate *brate = &sband->bitrates[i]; - int this_rate = brate->bitrate; + for (i = 0; i< sband->n_bitrates; i++) { + if (target_rate != sband->bitrates[i].bitrate) + continue; - if (target_rate == this_rate) { - sdata->max_ratectrl_rateidx = i; - if (mask->fixed) - sdata->force_unicast_rateidx = i; - err = 0; - break; - } + /* requested bitrate found */ + sdata->max_ratectrl_rateidx = i; + if (mask->fixed) + sdata->force_unicast_rateidx = i; + return 0; } - return err; + return -EINVAL; +} + +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 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 = { @@ -1437,4 +1509,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, }; |