diff options
Diffstat (limited to 'net/mac80211/cfg.c')
| -rw-r--r-- | net/mac80211/cfg.c | 198 |
1 files changed, 132 insertions, 66 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9ae1a4760b58..b7116ef84a3b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * mac80211 configuration hooks for cfg80211 | 2 | * mac80211 configuration hooks for cfg80211 |
| 3 | * | 3 | * |
| 4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
| 5 | * | 5 | * |
| 6 | * This file is GPLv2 as found in COPYING. | 6 | * This file is GPLv2 as found in COPYING. |
| 7 | */ | 7 | */ |
| @@ -78,17 +78,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
| 78 | enum nl80211_iftype type, u32 *flags, | 78 | enum nl80211_iftype type, u32 *flags, |
| 79 | struct vif_params *params) | 79 | struct vif_params *params) |
| 80 | { | 80 | { |
| 81 | struct ieee80211_sub_if_data *sdata; | 81 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 82 | int ret; | 82 | int ret; |
| 83 | 83 | ||
| 84 | if (netif_running(dev)) | 84 | if (ieee80211_sdata_running(sdata)) |
| 85 | return -EBUSY; | 85 | return -EBUSY; |
| 86 | 86 | ||
| 87 | if (!nl80211_params_check(type, params)) | 87 | if (!nl80211_params_check(type, params)) |
| 88 | return -EINVAL; | 88 | return -EINVAL; |
| 89 | 89 | ||
| 90 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 91 | |||
| 92 | ret = ieee80211_if_change_type(sdata, type); | 90 | ret = ieee80211_if_change_type(sdata, type); |
| 93 | if (ret) | 91 | if (ret) |
| 94 | return ret; | 92 | return ret; |
| @@ -150,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 150 | rcu_read_lock(); | 148 | rcu_read_lock(); |
| 151 | 149 | ||
| 152 | if (mac_addr) { | 150 | if (mac_addr) { |
| 153 | sta = sta_info_get(sdata->local, mac_addr); | 151 | sta = sta_info_get_bss(sdata, mac_addr); |
| 154 | if (!sta) { | 152 | if (!sta) { |
| 155 | ieee80211_key_free(key); | 153 | ieee80211_key_free(key); |
| 156 | err = -ENOENT; | 154 | err = -ENOENT; |
| @@ -181,7 +179,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 181 | if (mac_addr) { | 179 | if (mac_addr) { |
| 182 | ret = -ENOENT; | 180 | ret = -ENOENT; |
| 183 | 181 | ||
| 184 | sta = sta_info_get(sdata->local, mac_addr); | 182 | sta = sta_info_get_bss(sdata, mac_addr); |
| 185 | if (!sta) | 183 | if (!sta) |
| 186 | goto out_unlock; | 184 | goto out_unlock; |
| 187 | 185 | ||
| @@ -228,7 +226,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
| 228 | rcu_read_lock(); | 226 | rcu_read_lock(); |
| 229 | 227 | ||
| 230 | if (mac_addr) { | 228 | if (mac_addr) { |
| 231 | sta = sta_info_get(sdata->local, mac_addr); | 229 | sta = sta_info_get_bss(sdata, mac_addr); |
| 232 | if (!sta) | 230 | if (!sta) |
| 233 | goto out; | 231 | goto out; |
| 234 | 232 | ||
| @@ -415,15 +413,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, | 413 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
| 416 | u8 *mac, struct station_info *sinfo) | 414 | u8 *mac, struct station_info *sinfo) |
| 417 | { | 415 | { |
| 418 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 416 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 419 | struct sta_info *sta; | 417 | struct sta_info *sta; |
| 420 | int ret = -ENOENT; | 418 | int ret = -ENOENT; |
| 421 | 419 | ||
| 422 | rcu_read_lock(); | 420 | rcu_read_lock(); |
| 423 | 421 | ||
| 424 | /* XXX: verify sta->dev == dev */ | 422 | sta = sta_info_get_bss(sdata, mac); |
| 425 | |||
| 426 | sta = sta_info_get(local, mac); | ||
| 427 | if (sta) { | 423 | if (sta) { |
| 428 | ret = 0; | 424 | ret = 0; |
| 429 | sta_set_sinfo(sta, sinfo); | 425 | sta_set_sinfo(sta, sinfo); |
| @@ -519,6 +515,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
| 519 | if (old) | 515 | if (old) |
| 520 | memcpy(new->tail, old->tail, new_tail_len); | 516 | memcpy(new->tail, old->tail, new_tail_len); |
| 521 | 517 | ||
| 518 | sdata->vif.bss_conf.dtim_period = new->dtim_period; | ||
| 519 | |||
| 522 | rcu_assign_pointer(sdata->u.ap.beacon, new); | 520 | rcu_assign_pointer(sdata->u.ap.beacon, new); |
| 523 | 521 | ||
| 524 | synchronize_rcu(); | 522 | synchronize_rcu(); |
| @@ -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)) |
| @@ -751,9 +749,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 751 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 749 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
| 752 | sdata->vif.type == NL80211_IFTYPE_AP; | 750 | sdata->vif.type == NL80211_IFTYPE_AP; |
| 753 | 751 | ||
| 754 | rcu_read_lock(); | 752 | err = sta_info_insert_rcu(sta); |
| 755 | |||
| 756 | err = sta_info_insert(sta); | ||
| 757 | if (err) { | 753 | if (err) { |
| 758 | rcu_read_unlock(); | 754 | rcu_read_unlock(); |
| 759 | return err; | 755 | return err; |
| @@ -772,27 +768,13 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
| 772 | { | 768 | { |
| 773 | struct ieee80211_local *local = wiphy_priv(wiphy); | 769 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 774 | struct ieee80211_sub_if_data *sdata; | 770 | struct ieee80211_sub_if_data *sdata; |
| 775 | struct sta_info *sta; | ||
| 776 | 771 | ||
| 777 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 772 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 778 | 773 | ||
| 779 | if (mac) { | 774 | if (mac) |
| 780 | rcu_read_lock(); | 775 | return sta_info_destroy_addr_bss(sdata, mac); |
| 781 | |||
| 782 | /* XXX: get sta belonging to dev */ | ||
| 783 | sta = sta_info_get(local, mac); | ||
| 784 | if (!sta) { | ||
| 785 | rcu_read_unlock(); | ||
| 786 | return -ENOENT; | ||
| 787 | } | ||
| 788 | |||
| 789 | sta_info_unlink(&sta); | ||
| 790 | rcu_read_unlock(); | ||
| 791 | |||
| 792 | sta_info_destroy(sta); | ||
| 793 | } else | ||
| 794 | sta_info_flush(local, sdata); | ||
| 795 | 776 | ||
| 777 | sta_info_flush(local, sdata); | ||
| 796 | return 0; | 778 | return 0; |
| 797 | } | 779 | } |
| 798 | 780 | ||
| @@ -801,14 +783,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
| 801 | u8 *mac, | 783 | u8 *mac, |
| 802 | struct station_parameters *params) | 784 | struct station_parameters *params) |
| 803 | { | 785 | { |
| 786 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 804 | struct ieee80211_local *local = wiphy_priv(wiphy); | 787 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 805 | struct sta_info *sta; | 788 | struct sta_info *sta; |
| 806 | struct ieee80211_sub_if_data *vlansdata; | 789 | struct ieee80211_sub_if_data *vlansdata; |
| 807 | 790 | ||
| 808 | rcu_read_lock(); | 791 | rcu_read_lock(); |
| 809 | 792 | ||
| 810 | /* XXX: get sta belonging to dev */ | 793 | sta = sta_info_get_bss(sdata, mac); |
| 811 | sta = sta_info_get(local, mac); | ||
| 812 | if (!sta) { | 794 | if (!sta) { |
| 813 | rcu_read_unlock(); | 795 | rcu_read_unlock(); |
| 814 | return -ENOENT; | 796 | return -ENOENT; |
| @@ -847,7 +829,6 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
| 847 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | 829 | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, |
| 848 | u8 *dst, u8 *next_hop) | 830 | u8 *dst, u8 *next_hop) |
| 849 | { | 831 | { |
| 850 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
| 851 | struct ieee80211_sub_if_data *sdata; | 832 | struct ieee80211_sub_if_data *sdata; |
| 852 | struct mesh_path *mpath; | 833 | struct mesh_path *mpath; |
| 853 | struct sta_info *sta; | 834 | struct sta_info *sta; |
| @@ -856,7 +837,7 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
| 856 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 837 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 857 | 838 | ||
| 858 | rcu_read_lock(); | 839 | rcu_read_lock(); |
| 859 | sta = sta_info_get(local, next_hop); | 840 | sta = sta_info_get(sdata, next_hop); |
| 860 | if (!sta) { | 841 | if (!sta) { |
| 861 | rcu_read_unlock(); | 842 | rcu_read_unlock(); |
| 862 | return -ENOENT; | 843 | return -ENOENT; |
| @@ -895,7 +876,6 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
| 895 | struct net_device *dev, | 876 | struct net_device *dev, |
| 896 | u8 *dst, u8 *next_hop) | 877 | u8 *dst, u8 *next_hop) |
| 897 | { | 878 | { |
| 898 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
| 899 | struct ieee80211_sub_if_data *sdata; | 879 | struct ieee80211_sub_if_data *sdata; |
| 900 | struct mesh_path *mpath; | 880 | struct mesh_path *mpath; |
| 901 | struct sta_info *sta; | 881 | struct sta_info *sta; |
| @@ -904,7 +884,7 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
| 904 | 884 | ||
| 905 | rcu_read_lock(); | 885 | rcu_read_lock(); |
| 906 | 886 | ||
| 907 | sta = sta_info_get(local, next_hop); | 887 | sta = sta_info_get(sdata, next_hop); |
| 908 | if (!sta) { | 888 | if (!sta) { |
| 909 | rcu_read_unlock(); | 889 | rcu_read_unlock(); |
| 910 | return -ENOENT; | 890 | return -ENOENT; |
| @@ -1092,6 +1072,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
| 1092 | params->use_short_preamble; | 1072 | params->use_short_preamble; |
| 1093 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 1073 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
| 1094 | } | 1074 | } |
| 1075 | |||
| 1076 | if (!sdata->vif.bss_conf.use_short_slot && | ||
| 1077 | sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { | ||
| 1078 | sdata->vif.bss_conf.use_short_slot = true; | ||
| 1079 | changed |= BSS_CHANGED_ERP_SLOT; | ||
| 1080 | } | ||
| 1081 | |||
| 1095 | if (params->use_short_slot_time >= 0) { | 1082 | if (params->use_short_slot_time >= 0) { |
| 1096 | sdata->vif.bss_conf.use_short_slot = | 1083 | sdata->vif.bss_conf.use_short_slot = |
| 1097 | params->use_short_slot_time; | 1084 | params->use_short_slot_time; |
| @@ -1135,6 +1122,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
| 1135 | p.cw_max = params->cwmax; | 1122 | p.cw_max = params->cwmax; |
| 1136 | p.cw_min = params->cwmin; | 1123 | p.cw_min = params->cwmin; |
| 1137 | p.txop = params->txop; | 1124 | p.txop = params->txop; |
| 1125 | |||
| 1126 | /* | ||
| 1127 | * Setting tx queue params disables u-apsd because it's only | ||
| 1128 | * called in master mode. | ||
| 1129 | */ | ||
| 1130 | p.uapsd = false; | ||
| 1131 | |||
| 1138 | if (drv_conf_tx(local, params->queue, &p)) { | 1132 | if (drv_conf_tx(local, params->queue, &p)) { |
| 1139 | printk(KERN_DEBUG "%s: failed to set TX queue " | 1133 | printk(KERN_DEBUG "%s: failed to set TX queue " |
| 1140 | "parameters for queue %d\n", | 1134 | "parameters for queue %d\n", |
| @@ -1237,6 +1231,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
| 1237 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1231 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| 1238 | int err; | 1232 | int err; |
| 1239 | 1233 | ||
| 1234 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { | ||
| 1235 | err = drv_set_coverage_class(local, wiphy->coverage_class); | ||
| 1236 | |||
| 1237 | if (err) | ||
| 1238 | return err; | ||
| 1239 | } | ||
| 1240 | |||
| 1240 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | 1241 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { |
| 1241 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); | 1242 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); |
| 1242 | 1243 | ||
| @@ -1324,6 +1325,50 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len) | |||
| 1324 | } | 1325 | } |
| 1325 | #endif | 1326 | #endif |
| 1326 | 1327 | ||
| 1328 | int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | ||
| 1329 | enum ieee80211_smps_mode smps_mode) | ||
| 1330 | { | ||
| 1331 | const u8 *ap; | ||
| 1332 | enum ieee80211_smps_mode old_req; | ||
| 1333 | int err; | ||
| 1334 | |||
| 1335 | old_req = sdata->u.mgd.req_smps; | ||
| 1336 | sdata->u.mgd.req_smps = smps_mode; | ||
| 1337 | |||
| 1338 | if (old_req == smps_mode && | ||
| 1339 | smps_mode != IEEE80211_SMPS_AUTOMATIC) | ||
| 1340 | return 0; | ||
| 1341 | |||
| 1342 | /* | ||
| 1343 | * If not associated, or current association is not an HT | ||
| 1344 | * association, there's no need to send an action frame. | ||
| 1345 | */ | ||
| 1346 | if (!sdata->u.mgd.associated || | ||
| 1347 | sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) { | ||
| 1348 | mutex_lock(&sdata->local->iflist_mtx); | ||
| 1349 | ieee80211_recalc_smps(sdata->local, sdata); | ||
| 1350 | mutex_unlock(&sdata->local->iflist_mtx); | ||
| 1351 | return 0; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | ap = sdata->u.mgd.associated->bssid; | ||
| 1355 | |||
| 1356 | if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||
| 1357 | if (sdata->u.mgd.powersave) | ||
| 1358 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
| 1359 | else | ||
| 1360 | smps_mode = IEEE80211_SMPS_OFF; | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | /* send SM PS frame to AP */ | ||
| 1364 | err = ieee80211_send_smps_action(sdata, smps_mode, | ||
| 1365 | ap, ap); | ||
| 1366 | if (err) | ||
| 1367 | sdata->u.mgd.req_smps = old_req; | ||
| 1368 | |||
| 1369 | return err; | ||
| 1370 | } | ||
| 1371 | |||
| 1327 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | 1372 | static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, |
| 1328 | bool enabled, int timeout) | 1373 | bool enabled, int timeout) |
| 1329 | { | 1374 | { |
| @@ -1344,6 +1389,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
| 1344 | sdata->u.mgd.powersave = enabled; | 1389 | sdata->u.mgd.powersave = enabled; |
| 1345 | conf->dynamic_ps_timeout = timeout; | 1390 | conf->dynamic_ps_timeout = timeout; |
| 1346 | 1391 | ||
| 1392 | /* no change, but if automatic follow powersave */ | ||
| 1393 | mutex_lock(&sdata->u.mgd.mtx); | ||
| 1394 | __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); | ||
| 1395 | mutex_unlock(&sdata->u.mgd.mtx); | ||
| 1396 | |||
| 1347 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 1397 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
| 1348 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 1398 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
| 1349 | 1399 | ||
| @@ -1359,39 +1409,52 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
| 1359 | { | 1409 | { |
| 1360 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1410 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 1361 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1411 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
| 1362 | int i, err = -EINVAL; | 1412 | int i; |
| 1363 | u32 target_rate; | 1413 | |
| 1364 | struct ieee80211_supported_band *sband; | 1414 | /* |
| 1415 | * This _could_ be supported by providing a hook for | ||
| 1416 | * drivers for this function, but at this point it | ||
| 1417 | * doesn't seem worth bothering. | ||
| 1418 | */ | ||
| 1419 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
| 1420 | return -EOPNOTSUPP; | ||
| 1365 | 1421 | ||
| 1366 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
| 1367 | 1422 | ||
| 1368 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | 1423 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) |
| 1369 | * target_rate = X, rate->fixed = 1 means only rate X | 1424 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
| 1370 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | ||
| 1371 | sdata->max_ratectrl_rateidx = -1; | ||
| 1372 | sdata->force_unicast_rateidx = -1; | ||
| 1373 | 1425 | ||
| 1374 | if (mask->fixed) | 1426 | return 0; |
| 1375 | target_rate = mask->fixed / 100; | 1427 | } |
| 1376 | else if (mask->maxrate) | ||
| 1377 | target_rate = mask->maxrate / 100; | ||
| 1378 | else | ||
| 1379 | return 0; | ||
| 1380 | 1428 | ||
| 1381 | for (i=0; i< sband->n_bitrates; i++) { | 1429 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
| 1382 | struct ieee80211_rate *brate = &sband->bitrates[i]; | 1430 | struct net_device *dev, |
| 1383 | int this_rate = brate->bitrate; | 1431 | struct ieee80211_channel *chan, |
| 1432 | enum nl80211_channel_type channel_type, | ||
| 1433 | unsigned int duration, | ||
| 1434 | u64 *cookie) | ||
| 1435 | { | ||
| 1436 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1384 | 1437 | ||
| 1385 | if (target_rate == this_rate) { | 1438 | return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, |
| 1386 | sdata->max_ratectrl_rateidx = i; | 1439 | duration, cookie); |
| 1387 | if (mask->fixed) | 1440 | } |
| 1388 | sdata->force_unicast_rateidx = i; | ||
| 1389 | err = 0; | ||
| 1390 | break; | ||
| 1391 | } | ||
| 1392 | } | ||
| 1393 | 1441 | ||
| 1394 | return err; | 1442 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, |
| 1443 | struct net_device *dev, | ||
| 1444 | u64 cookie) | ||
| 1445 | { | ||
| 1446 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1447 | |||
| 1448 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, | ||
| 1452 | struct ieee80211_channel *chan, | ||
| 1453 | enum nl80211_channel_type channel_type, | ||
| 1454 | const u8 *buf, size_t len, u64 *cookie) | ||
| 1455 | { | ||
| 1456 | return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan, | ||
| 1457 | channel_type, buf, len, cookie); | ||
| 1395 | } | 1458 | } |
| 1396 | 1459 | ||
| 1397 | struct cfg80211_ops mac80211_config_ops = { | 1460 | struct cfg80211_ops mac80211_config_ops = { |
| @@ -1440,4 +1503,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
| 1440 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) | 1503 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) |
| 1441 | .set_power_mgmt = ieee80211_set_power_mgmt, | 1504 | .set_power_mgmt = ieee80211_set_power_mgmt, |
| 1442 | .set_bitrate_mask = ieee80211_set_bitrate_mask, | 1505 | .set_bitrate_mask = ieee80211_set_bitrate_mask, |
| 1506 | .remain_on_channel = ieee80211_remain_on_channel, | ||
| 1507 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | ||
| 1508 | .action = ieee80211_action, | ||
| 1443 | }; | 1509 | }; |
