diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 112 |
1 files changed, 82 insertions, 30 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6dc3579c0ac5..63843e3e576a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -150,7 +150,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
150 | rcu_read_lock(); | 150 | rcu_read_lock(); |
151 | 151 | ||
152 | if (mac_addr) { | 152 | if (mac_addr) { |
153 | sta = sta_info_get(sdata->local, mac_addr); | 153 | sta = sta_info_get(sdata, mac_addr); |
154 | if (!sta) { | 154 | if (!sta) { |
155 | ieee80211_key_free(key); | 155 | ieee80211_key_free(key); |
156 | err = -ENOENT; | 156 | err = -ENOENT; |
@@ -181,7 +181,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
181 | if (mac_addr) { | 181 | if (mac_addr) { |
182 | ret = -ENOENT; | 182 | ret = -ENOENT; |
183 | 183 | ||
184 | sta = sta_info_get(sdata->local, mac_addr); | 184 | sta = sta_info_get(sdata, mac_addr); |
185 | if (!sta) | 185 | if (!sta) |
186 | goto out_unlock; | 186 | goto out_unlock; |
187 | 187 | ||
@@ -228,7 +228,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
228 | rcu_read_lock(); | 228 | rcu_read_lock(); |
229 | 229 | ||
230 | if (mac_addr) { | 230 | if (mac_addr) { |
231 | sta = sta_info_get(sdata->local, mac_addr); | 231 | sta = sta_info_get(sdata, mac_addr); |
232 | if (!sta) | 232 | if (!sta) |
233 | goto out; | 233 | goto out; |
234 | 234 | ||
@@ -415,15 +415,13 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | |||
415 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 415 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
416 | u8 *mac, struct station_info *sinfo) | 416 | u8 *mac, struct station_info *sinfo) |
417 | { | 417 | { |
418 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 418 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
419 | struct sta_info *sta; | 419 | struct sta_info *sta; |
420 | int ret = -ENOENT; | 420 | int ret = -ENOENT; |
421 | 421 | ||
422 | rcu_read_lock(); | 422 | rcu_read_lock(); |
423 | 423 | ||
424 | /* XXX: verify sta->dev == dev */ | 424 | sta = sta_info_get(sdata, mac); |
425 | |||
426 | sta = sta_info_get(local, mac); | ||
427 | if (sta) { | 425 | if (sta) { |
428 | ret = 0; | 426 | ret = 0; |
429 | sta_set_sinfo(sta, sinfo); | 427 | sta_set_sinfo(sta, sinfo); |
@@ -732,7 +730,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
732 | } else | 730 | } else |
733 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 731 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
734 | 732 | ||
735 | if (compare_ether_addr(mac, dev->dev_addr) == 0) | 733 | if (compare_ether_addr(mac, sdata->vif.addr) == 0) |
736 | return -EINVAL; | 734 | return -EINVAL; |
737 | 735 | ||
738 | if (is_multicast_ether_addr(mac)) | 736 | if (is_multicast_ether_addr(mac)) |
@@ -779,8 +777,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
779 | if (mac) { | 777 | if (mac) { |
780 | rcu_read_lock(); | 778 | rcu_read_lock(); |
781 | 779 | ||
782 | /* XXX: get sta belonging to dev */ | 780 | sta = sta_info_get(sdata, mac); |
783 | sta = sta_info_get(local, mac); | ||
784 | if (!sta) { | 781 | if (!sta) { |
785 | rcu_read_unlock(); | 782 | rcu_read_unlock(); |
786 | return -ENOENT; | 783 | return -ENOENT; |
@@ -801,14 +798,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
801 | u8 *mac, | 798 | u8 *mac, |
802 | struct station_parameters *params) | 799 | struct station_parameters *params) |
803 | { | 800 | { |
801 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
804 | struct ieee80211_local *local = wiphy_priv(wiphy); | 802 | struct ieee80211_local *local = wiphy_priv(wiphy); |
805 | struct sta_info *sta; | 803 | struct sta_info *sta; |
806 | struct ieee80211_sub_if_data *vlansdata; | 804 | struct ieee80211_sub_if_data *vlansdata; |
807 | 805 | ||
808 | rcu_read_lock(); | 806 | rcu_read_lock(); |
809 | 807 | ||
810 | /* XXX: get sta belonging to dev */ | 808 | sta = sta_info_get(sdata, mac); |
811 | sta = sta_info_get(local, mac); | ||
812 | if (!sta) { | 809 | if (!sta) { |
813 | rcu_read_unlock(); | 810 | rcu_read_unlock(); |
814 | return -ENOENT; | 811 | return -ENOENT; |
@@ -847,7 +844,6 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
847 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | 844 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, |
848 | u8 *dst, u8 *next_hop) | 845 | u8 *dst, u8 *next_hop) |
849 | { | 846 | { |
850 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
851 | struct ieee80211_sub_if_data *sdata; | 847 | struct ieee80211_sub_if_data *sdata; |
852 | struct mesh_path *mpath; | 848 | struct mesh_path *mpath; |
853 | struct sta_info *sta; | 849 | struct sta_info *sta; |
@@ -856,7 +852,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
856 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 852 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
857 | 853 | ||
858 | rcu_read_lock(); | 854 | rcu_read_lock(); |
859 | sta = sta_info_get(local, next_hop); | 855 | sta = sta_info_get(sdata, next_hop); |
860 | if (!sta) { | 856 | if (!sta) { |
861 | rcu_read_unlock(); | 857 | rcu_read_unlock(); |
862 | return -ENOENT; | 858 | return -ENOENT; |
@@ -895,7 +891,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
895 | struct net_device *dev, | 891 | struct net_device *dev, |
896 | u8 *dst, u8 *next_hop) | 892 | u8 *dst, u8 *next_hop) |
897 | { | 893 | { |
898 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
899 | struct ieee80211_sub_if_data *sdata; | 894 | struct ieee80211_sub_if_data *sdata; |
900 | struct mesh_path *mpath; | 895 | struct mesh_path *mpath; |
901 | struct sta_info *sta; | 896 | struct sta_info *sta; |
@@ -904,7 +899,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
904 | 899 | ||
905 | rcu_read_lock(); | 900 | rcu_read_lock(); |
906 | 901 | ||
907 | sta = sta_info_get(local, next_hop); | 902 | sta = sta_info_get(sdata, next_hop); |
908 | if (!sta) { | 903 | if (!sta) { |
909 | rcu_read_unlock(); | 904 | rcu_read_unlock(); |
910 | return -ENOENT; | 905 | return -ENOENT; |
@@ -1324,6 +1319,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) | |||
1324 | } | 1319 | } |
1325 | #endif | 1320 | #endif |
1326 | 1321 | ||
1322 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | ||
1323 | enum ieee80211_smps_mode smps_mode) | ||
1324 | { | ||
1325 | const u8 *ap; | ||
1326 | enum ieee80211_smps_mode old_req; | ||
1327 | int err; | ||
1328 | |||
1329 | old_req = sdata->u.mgd.req_smps; | ||
1330 | sdata->u.mgd.req_smps = smps_mode; | ||
1331 | |||
1332 | if (old_req == smps_mode && | ||
1333 | smps_mode != IEEE80211_SMPS_AUTOMATIC) | ||
1334 | return 0; | ||
1335 | |||
1336 | /* | ||
1337 | * If not associated, or current association is not an HT | ||
1338 | * association, there's no need to send an action frame. | ||
1339 | */ | ||
1340 | if (!sdata->u.mgd.associated || | ||
1341 | sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) { | ||
1342 | mutex_lock(&sdata->local->iflist_mtx); | ||
1343 | ieee80211_recalc_smps(sdata->local, sdata); | ||
1344 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1345 | return 0; | ||
1346 | } | ||
1347 | |||
1348 | ap = sdata->u.mgd.associated->cbss.bssid; | ||
1349 | |||
1350 | if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
1351 | if (sdata->u.mgd.powersave) | ||
1352 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
1353 | else | ||
1354 | smps_mode = IEEE80211_SMPS_OFF; | ||
1355 | } | ||
1356 | |||
1357 | /* send SM PS frame to AP */ | ||
1358 | err = ieee80211_send_smps_action(sdata, smps_mode, | ||
1359 | ap, ap); | ||
1360 | if (err) | ||
1361 | sdata->u.mgd.req_smps = old_req; | ||
1362 | |||
1363 | return err; | ||
1364 | } | ||
1365 | |||
1327 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | 1366 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, |
1328 | bool enabled, int timeout) | 1367 | bool enabled, int timeout) |
1329 | { | 1368 | { |
@@ -1341,6 +1380,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
1341 | sdata->u.mgd.powersave = enabled; | 1380 | sdata->u.mgd.powersave = enabled; |
1342 | conf->dynamic_ps_timeout = timeout; | 1381 | conf->dynamic_ps_timeout = timeout; |
1343 | 1382 | ||
1383 | /* no change, but if automatic follow powersave */ | ||
1384 | mutex_lock(&sdata->u.mgd.mtx); | ||
1385 | __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); | ||
1386 | mutex_unlock(&sdata->u.mgd.mtx); | ||
1387 | |||
1344 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 1388 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
1345 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 1389 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
1346 | 1390 | ||
@@ -1356,15 +1400,25 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1356 | { | 1400 | { |
1357 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1401 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1358 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1402 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1359 | int i, err = -EINVAL; | 1403 | int i; |
1360 | u32 target_rate; | 1404 | u32 target_rate; |
1361 | struct ieee80211_supported_band *sband; | 1405 | struct ieee80211_supported_band *sband; |
1362 | 1406 | ||
1407 | /* | ||
1408 | * This _could_ be supported by providing a hook for | ||
1409 | * drivers for this function, but at this point it | ||
1410 | * doesn't seem worth bothering. | ||
1411 | */ | ||
1412 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
1413 | return -EOPNOTSUPP; | ||
1414 | |||
1363 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1415 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1364 | 1416 | ||
1365 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | 1417 | /* |
1418 | * target_rate = -1, rate->fixed = 0 means auto only, so use all rates | ||
1366 | * target_rate = X, rate->fixed = 1 means only rate X | 1419 | * target_rate = X, rate->fixed = 1 means only rate X |
1367 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | 1420 | * target_rate = X, rate->fixed = 0 means all rates <= X |
1421 | */ | ||
1368 | sdata->max_ratectrl_rateidx = -1; | 1422 | sdata->max_ratectrl_rateidx = -1; |
1369 | sdata->force_unicast_rateidx = -1; | 1423 | sdata->force_unicast_rateidx = -1; |
1370 | 1424 | ||
@@ -1375,20 +1429,18 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1375 | else | 1429 | else |
1376 | return 0; | 1430 | return 0; |
1377 | 1431 | ||
1378 | for (i=0; i< sband->n_bitrates; i++) { | 1432 | for (i = 0; i< sband->n_bitrates; i++) { |
1379 | struct ieee80211_rate *brate = &sband->bitrates[i]; | 1433 | if (target_rate != sband->bitrates[i].bitrate) |
1380 | int this_rate = brate->bitrate; | 1434 | continue; |
1381 | 1435 | ||
1382 | if (target_rate == this_rate) { | 1436 | /* requested bitrate found */ |
1383 | sdata->max_ratectrl_rateidx = i; | 1437 | sdata->max_ratectrl_rateidx = i; |
1384 | if (mask->fixed) | 1438 | if (mask->fixed) |
1385 | sdata->force_unicast_rateidx = i; | 1439 | sdata->force_unicast_rateidx = i; |
1386 | err = 0; | 1440 | return 0; |
1387 | break; | ||
1388 | } | ||
1389 | } | 1441 | } |
1390 | 1442 | ||
1391 | return err; | 1443 | return -EINVAL; |
1392 | } | 1444 | } |
1393 | 1445 | ||
1394 | struct cfg80211_ops mac80211_config_ops = { | 1446 | struct cfg80211_ops mac80211_config_ops = { |