diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 306 |
1 files changed, 228 insertions, 78 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9cd73b11506e..be70c70d3f5b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -136,7 +136,10 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
136 | mutex_lock(&sdata->local->sta_mtx); | 136 | mutex_lock(&sdata->local->sta_mtx); |
137 | 137 | ||
138 | if (mac_addr) { | 138 | if (mac_addr) { |
139 | sta = sta_info_get_bss(sdata, mac_addr); | 139 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
140 | sta = sta_info_get(sdata, mac_addr); | ||
141 | else | ||
142 | sta = sta_info_get_bss(sdata, mac_addr); | ||
140 | if (!sta) { | 143 | if (!sta) { |
141 | ieee80211_key_free(sdata->local, key); | 144 | ieee80211_key_free(sdata->local, key); |
142 | err = -ENOENT; | 145 | err = -ENOENT; |
@@ -157,13 +160,14 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
157 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 160 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
158 | u8 key_idx, bool pairwise, const u8 *mac_addr) | 161 | u8 key_idx, bool pairwise, const u8 *mac_addr) |
159 | { | 162 | { |
160 | struct ieee80211_sub_if_data *sdata; | 163 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
164 | struct ieee80211_local *local = sdata->local; | ||
161 | struct sta_info *sta; | 165 | struct sta_info *sta; |
166 | struct ieee80211_key *key = NULL; | ||
162 | int ret; | 167 | int ret; |
163 | 168 | ||
164 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 169 | mutex_lock(&local->sta_mtx); |
165 | 170 | mutex_lock(&local->key_mtx); | |
166 | mutex_lock(&sdata->local->sta_mtx); | ||
167 | 171 | ||
168 | if (mac_addr) { | 172 | if (mac_addr) { |
169 | ret = -ENOENT; | 173 | ret = -ENOENT; |
@@ -172,33 +176,24 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
172 | if (!sta) | 176 | if (!sta) |
173 | goto out_unlock; | 177 | goto out_unlock; |
174 | 178 | ||
175 | if (pairwise) { | 179 | if (pairwise) |
176 | if (sta->ptk) { | 180 | key = key_mtx_dereference(local, sta->ptk); |
177 | ieee80211_key_free(sdata->local, sta->ptk); | 181 | else |
178 | ret = 0; | 182 | key = key_mtx_dereference(local, sta->gtk[key_idx]); |
179 | } | 183 | } else |
180 | } else { | 184 | key = key_mtx_dereference(local, sdata->keys[key_idx]); |
181 | if (sta->gtk[key_idx]) { | ||
182 | ieee80211_key_free(sdata->local, | ||
183 | sta->gtk[key_idx]); | ||
184 | ret = 0; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | goto out_unlock; | ||
189 | } | ||
190 | 185 | ||
191 | if (!sdata->keys[key_idx]) { | 186 | if (!key) { |
192 | ret = -ENOENT; | 187 | ret = -ENOENT; |
193 | goto out_unlock; | 188 | goto out_unlock; |
194 | } | 189 | } |
195 | 190 | ||
196 | ieee80211_key_free(sdata->local, sdata->keys[key_idx]); | 191 | __ieee80211_key_free(key); |
197 | WARN_ON(sdata->keys[key_idx]); | ||
198 | 192 | ||
199 | ret = 0; | 193 | ret = 0; |
200 | out_unlock: | 194 | out_unlock: |
201 | mutex_unlock(&sdata->local->sta_mtx); | 195 | mutex_unlock(&local->key_mtx); |
196 | mutex_unlock(&local->sta_mtx); | ||
202 | 197 | ||
203 | return ret; | 198 | return ret; |
204 | } | 199 | } |
@@ -228,11 +223,11 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
228 | goto out; | 223 | goto out; |
229 | 224 | ||
230 | if (pairwise) | 225 | if (pairwise) |
231 | key = sta->ptk; | 226 | key = rcu_dereference(sta->ptk); |
232 | else if (key_idx < NUM_DEFAULT_KEYS) | 227 | else if (key_idx < NUM_DEFAULT_KEYS) |
233 | key = sta->gtk[key_idx]; | 228 | key = rcu_dereference(sta->gtk[key_idx]); |
234 | } else | 229 | } else |
235 | key = sdata->keys[key_idx]; | 230 | key = rcu_dereference(sdata->keys[key_idx]); |
236 | 231 | ||
237 | if (!key) | 232 | if (!key) |
238 | goto out; | 233 | goto out; |
@@ -316,9 +311,21 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy, | |||
316 | return 0; | 311 | return 0; |
317 | } | 312 | } |
318 | 313 | ||
314 | static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx) | ||
315 | { | ||
316 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) { | ||
317 | struct ieee80211_supported_band *sband; | ||
318 | sband = sta->local->hw.wiphy->bands[ | ||
319 | sta->local->hw.conf.channel->band]; | ||
320 | rate->legacy = sband->bitrates[idx].bitrate; | ||
321 | } else | ||
322 | rate->mcs = idx; | ||
323 | } | ||
324 | |||
319 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 325 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
320 | { | 326 | { |
321 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 327 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
328 | struct timespec uptime; | ||
322 | 329 | ||
323 | sinfo->generation = sdata->local->sta_generation; | 330 | sinfo->generation = sdata->local->sta_generation; |
324 | 331 | ||
@@ -330,7 +337,13 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
330 | STATION_INFO_TX_RETRIES | | 337 | STATION_INFO_TX_RETRIES | |
331 | STATION_INFO_TX_FAILED | | 338 | STATION_INFO_TX_FAILED | |
332 | STATION_INFO_TX_BITRATE | | 339 | STATION_INFO_TX_BITRATE | |
333 | STATION_INFO_RX_DROP_MISC; | 340 | STATION_INFO_RX_BITRATE | |
341 | STATION_INFO_RX_DROP_MISC | | ||
342 | STATION_INFO_BSS_PARAM | | ||
343 | STATION_INFO_CONNECTED_TIME; | ||
344 | |||
345 | do_posix_clock_monotonic_gettime(&uptime); | ||
346 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | ||
334 | 347 | ||
335 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 348 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
336 | sinfo->rx_bytes = sta->rx_bytes; | 349 | sinfo->rx_bytes = sta->rx_bytes; |
@@ -355,15 +368,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
355 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; | 368 | sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
356 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) | 369 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) |
357 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; | 370 | sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
371 | rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx); | ||
358 | 372 | ||
359 | if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) { | 373 | sinfo->rxrate.flags = 0; |
360 | struct ieee80211_supported_band *sband; | 374 | if (sta->last_rx_rate_flag & RX_FLAG_HT) |
361 | sband = sta->local->hw.wiphy->bands[ | 375 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS; |
362 | sta->local->hw.conf.channel->band]; | 376 | if (sta->last_rx_rate_flag & RX_FLAG_40MHZ) |
363 | sinfo->txrate.legacy = | 377 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; |
364 | sband->bitrates[sta->last_tx_rate.idx].bitrate; | 378 | if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI) |
365 | } else | 379 | sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
366 | sinfo->txrate.mcs = sta->last_tx_rate.idx; | 380 | rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx); |
367 | 381 | ||
368 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 382 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
369 | #ifdef CONFIG_MAC80211_MESH | 383 | #ifdef CONFIG_MAC80211_MESH |
@@ -376,6 +390,16 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
376 | sinfo->plink_state = sta->plink_state; | 390 | sinfo->plink_state = sta->plink_state; |
377 | #endif | 391 | #endif |
378 | } | 392 | } |
393 | |||
394 | sinfo->bss_param.flags = 0; | ||
395 | if (sdata->vif.bss_conf.use_cts_prot) | ||
396 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; | ||
397 | if (sdata->vif.bss_conf.use_short_preamble) | ||
398 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; | ||
399 | if (sdata->vif.bss_conf.use_short_slot) | ||
400 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; | ||
401 | sinfo->bss_param.dtim_period = sdata->local->hw.conf.ps_dtim_period; | ||
402 | sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; | ||
379 | } | 403 | } |
380 | 404 | ||
381 | 405 | ||
@@ -439,7 +463,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
439 | int size; | 463 | int size; |
440 | int err = -EINVAL; | 464 | int err = -EINVAL; |
441 | 465 | ||
442 | old = sdata->u.ap.beacon; | 466 | old = rtnl_dereference(sdata->u.ap.beacon); |
443 | 467 | ||
444 | /* head must not be zero-length */ | 468 | /* head must not be zero-length */ |
445 | if (params->head && !params->head_len) | 469 | if (params->head && !params->head_len) |
@@ -534,8 +558,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
534 | 558 | ||
535 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 559 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
536 | 560 | ||
537 | old = sdata->u.ap.beacon; | 561 | old = rtnl_dereference(sdata->u.ap.beacon); |
538 | |||
539 | if (old) | 562 | if (old) |
540 | return -EALREADY; | 563 | return -EALREADY; |
541 | 564 | ||
@@ -550,8 +573,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
550 | 573 | ||
551 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 574 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
552 | 575 | ||
553 | old = sdata->u.ap.beacon; | 576 | old = rtnl_dereference(sdata->u.ap.beacon); |
554 | |||
555 | if (!old) | 577 | if (!old) |
556 | return -ENOENT; | 578 | return -ENOENT; |
557 | 579 | ||
@@ -565,8 +587,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
565 | 587 | ||
566 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 588 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
567 | 589 | ||
568 | old = sdata->u.ap.beacon; | 590 | old = rtnl_dereference(sdata->u.ap.beacon); |
569 | |||
570 | if (!old) | 591 | if (!old) |
571 | return -ENOENT; | 592 | return -ENOENT; |
572 | 593 | ||
@@ -662,6 +683,12 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
662 | if (set & BIT(NL80211_STA_FLAG_MFP)) | 683 | if (set & BIT(NL80211_STA_FLAG_MFP)) |
663 | sta->flags |= WLAN_STA_MFP; | 684 | sta->flags |= WLAN_STA_MFP; |
664 | } | 685 | } |
686 | |||
687 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { | ||
688 | sta->flags &= ~WLAN_STA_AUTH; | ||
689 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) | ||
690 | sta->flags |= WLAN_STA_AUTH; | ||
691 | } | ||
665 | spin_unlock_irqrestore(&sta->flaglock, flags); | 692 | spin_unlock_irqrestore(&sta->flaglock, flags); |
666 | 693 | ||
667 | /* | 694 | /* |
@@ -699,15 +726,29 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
699 | params->ht_capa, | 726 | params->ht_capa, |
700 | &sta->sta.ht_cap); | 727 | &sta->sta.ht_cap); |
701 | 728 | ||
702 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | 729 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
703 | switch (params->plink_action) { | 730 | #ifdef CONFIG_MAC80211_MESH |
704 | case PLINK_ACTION_OPEN: | 731 | if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) |
705 | mesh_plink_open(sta); | 732 | switch (params->plink_state) { |
706 | break; | 733 | case NL80211_PLINK_LISTEN: |
707 | case PLINK_ACTION_BLOCK: | 734 | case NL80211_PLINK_ESTAB: |
708 | mesh_plink_block(sta); | 735 | case NL80211_PLINK_BLOCKED: |
709 | break; | 736 | sta->plink_state = params->plink_state; |
710 | } | 737 | break; |
738 | default: | ||
739 | /* nothing */ | ||
740 | break; | ||
741 | } | ||
742 | else | ||
743 | switch (params->plink_action) { | ||
744 | case PLINK_ACTION_OPEN: | ||
745 | mesh_plink_open(sta); | ||
746 | break; | ||
747 | case PLINK_ACTION_BLOCK: | ||
748 | mesh_plink_block(sta); | ||
749 | break; | ||
750 | } | ||
751 | #endif | ||
711 | } | 752 | } |
712 | } | 753 | } |
713 | 754 | ||
@@ -821,6 +862,10 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
821 | 862 | ||
822 | rcu_read_unlock(); | 863 | rcu_read_unlock(); |
823 | 864 | ||
865 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
866 | params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
867 | ieee80211_recalc_ps(local, -1); | ||
868 | |||
824 | return 0; | 869 | return 0; |
825 | } | 870 | } |
826 | 871 | ||
@@ -904,8 +949,10 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
904 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | 949 | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, |
905 | struct mpath_info *pinfo) | 950 | struct mpath_info *pinfo) |
906 | { | 951 | { |
907 | if (mpath->next_hop) | 952 | struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop); |
908 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 953 | |
954 | if (next_hop_sta) | ||
955 | memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN); | ||
909 | else | 956 | else |
910 | memset(next_hop, 0, ETH_ALEN); | 957 | memset(next_hop, 0, ETH_ALEN); |
911 | 958 | ||
@@ -1006,26 +1053,30 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1006 | u8 *new_ie; | 1053 | u8 *new_ie; |
1007 | const u8 *old_ie; | 1054 | const u8 *old_ie; |
1008 | 1055 | ||
1009 | /* first allocate the new vendor information element */ | 1056 | /* allocate information elements */ |
1010 | new_ie = NULL; | 1057 | new_ie = NULL; |
1011 | old_ie = ifmsh->vendor_ie; | 1058 | old_ie = ifmsh->ie; |
1012 | 1059 | ||
1013 | ifmsh->vendor_ie_len = setup->vendor_ie_len; | 1060 | if (setup->ie_len) { |
1014 | if (setup->vendor_ie_len) { | 1061 | new_ie = kmemdup(setup->ie, setup->ie_len, |
1015 | new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len, | ||
1016 | GFP_KERNEL); | 1062 | GFP_KERNEL); |
1017 | if (!new_ie) | 1063 | if (!new_ie) |
1018 | return -ENOMEM; | 1064 | return -ENOMEM; |
1019 | } | 1065 | } |
1066 | ifmsh->ie_len = setup->ie_len; | ||
1067 | ifmsh->ie = new_ie; | ||
1068 | kfree(old_ie); | ||
1020 | 1069 | ||
1021 | /* now copy the rest of the setup parameters */ | 1070 | /* now copy the rest of the setup parameters */ |
1022 | ifmsh->mesh_id_len = setup->mesh_id_len; | 1071 | ifmsh->mesh_id_len = setup->mesh_id_len; |
1023 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | 1072 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); |
1024 | ifmsh->mesh_pp_id = setup->path_sel_proto; | 1073 | ifmsh->mesh_pp_id = setup->path_sel_proto; |
1025 | ifmsh->mesh_pm_id = setup->path_metric; | 1074 | ifmsh->mesh_pm_id = setup->path_metric; |
1026 | ifmsh->vendor_ie = new_ie; | 1075 | ifmsh->security = IEEE80211_MESH_SEC_NONE; |
1027 | 1076 | if (setup->is_authenticated) | |
1028 | kfree(old_ie); | 1077 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; |
1078 | if (setup->is_secure) | ||
1079 | ifmsh->security |= IEEE80211_MESH_SEC_SECURED; | ||
1029 | 1080 | ||
1030 | return 0; | 1081 | return 0; |
1031 | } | 1082 | } |
@@ -1215,6 +1266,9 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1215 | { | 1266 | { |
1216 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1267 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1217 | struct ieee80211_sub_if_data *sdata = NULL; | 1268 | struct ieee80211_sub_if_data *sdata = NULL; |
1269 | struct ieee80211_channel *old_oper; | ||
1270 | enum nl80211_channel_type old_oper_type; | ||
1271 | enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT; | ||
1218 | 1272 | ||
1219 | if (netdev) | 1273 | if (netdev) |
1220 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); | 1274 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); |
@@ -1232,22 +1286,33 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1232 | break; | 1286 | break; |
1233 | } | 1287 | } |
1234 | 1288 | ||
1235 | local->oper_channel = chan; | 1289 | if (sdata) |
1290 | old_vif_oper_type = sdata->vif.bss_conf.channel_type; | ||
1291 | old_oper_type = local->_oper_channel_type; | ||
1236 | 1292 | ||
1237 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) | 1293 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) |
1238 | return -EBUSY; | 1294 | return -EBUSY; |
1239 | 1295 | ||
1240 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1296 | old_oper = local->oper_channel; |
1241 | if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) | 1297 | local->oper_channel = chan; |
1298 | |||
1299 | /* Update driver if changes were actually made. */ | ||
1300 | if ((old_oper != local->oper_channel) || | ||
1301 | (old_oper_type != local->_oper_channel_type)) | ||
1302 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
1303 | |||
1304 | if ((sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) && | ||
1305 | old_vif_oper_type != sdata->vif.bss_conf.channel_type) | ||
1242 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); | 1306 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); |
1243 | 1307 | ||
1244 | return 0; | 1308 | return 0; |
1245 | } | 1309 | } |
1246 | 1310 | ||
1247 | #ifdef CONFIG_PM | 1311 | #ifdef CONFIG_PM |
1248 | static int ieee80211_suspend(struct wiphy *wiphy) | 1312 | static int ieee80211_suspend(struct wiphy *wiphy, |
1313 | struct cfg80211_wowlan *wowlan) | ||
1249 | { | 1314 | { |
1250 | return __ieee80211_suspend(wiphy_priv(wiphy)); | 1315 | return __ieee80211_suspend(wiphy_priv(wiphy), wowlan); |
1251 | } | 1316 | } |
1252 | 1317 | ||
1253 | static int ieee80211_resume(struct wiphy *wiphy) | 1318 | static int ieee80211_resume(struct wiphy *wiphy) |
@@ -1274,8 +1339,11 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1274 | case NL80211_IFTYPE_P2P_GO: | 1339 | case NL80211_IFTYPE_P2P_GO: |
1275 | if (sdata->local->ops->hw_scan) | 1340 | if (sdata->local->ops->hw_scan) |
1276 | break; | 1341 | break; |
1277 | /* FIXME: implement NoA while scanning in software */ | 1342 | /* |
1278 | return -EOPNOTSUPP; | 1343 | * FIXME: implement NoA while scanning in software, |
1344 | * for now fall through to allow scanning only when | ||
1345 | * beaconing hasn't been configured yet | ||
1346 | */ | ||
1279 | case NL80211_IFTYPE_AP: | 1347 | case NL80211_IFTYPE_AP: |
1280 | if (sdata->u.ap.beacon) | 1348 | if (sdata->u.ap.beacon) |
1281 | return -EOPNOTSUPP; | 1349 | return -EOPNOTSUPP; |
@@ -1287,6 +1355,30 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1287 | return ieee80211_request_scan(sdata, req); | 1355 | return ieee80211_request_scan(sdata, req); |
1288 | } | 1356 | } |
1289 | 1357 | ||
1358 | static int | ||
1359 | ieee80211_sched_scan_start(struct wiphy *wiphy, | ||
1360 | struct net_device *dev, | ||
1361 | struct cfg80211_sched_scan_request *req) | ||
1362 | { | ||
1363 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1364 | |||
1365 | if (!sdata->local->ops->sched_scan_start) | ||
1366 | return -EOPNOTSUPP; | ||
1367 | |||
1368 | return ieee80211_request_sched_scan_start(sdata, req); | ||
1369 | } | ||
1370 | |||
1371 | static int | ||
1372 | ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) | ||
1373 | { | ||
1374 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1375 | |||
1376 | if (!sdata->local->ops->sched_scan_stop) | ||
1377 | return -EOPNOTSUPP; | ||
1378 | |||
1379 | return ieee80211_request_sched_scan_stop(sdata); | ||
1380 | } | ||
1381 | |||
1290 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | 1382 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, |
1291 | struct cfg80211_auth_request *req) | 1383 | struct cfg80211_auth_request *req) |
1292 | { | 1384 | { |
@@ -1471,6 +1563,8 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
1471 | enum ieee80211_smps_mode old_req; | 1563 | enum ieee80211_smps_mode old_req; |
1472 | int err; | 1564 | int err; |
1473 | 1565 | ||
1566 | lockdep_assert_held(&sdata->u.mgd.mtx); | ||
1567 | |||
1474 | old_req = sdata->u.mgd.req_smps; | 1568 | old_req = sdata->u.mgd.req_smps; |
1475 | sdata->u.mgd.req_smps = smps_mode; | 1569 | sdata->u.mgd.req_smps = smps_mode; |
1476 | 1570 | ||
@@ -1576,16 +1670,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1576 | { | 1670 | { |
1577 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1671 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1578 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1672 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1579 | int i; | 1673 | int i, ret; |
1580 | |||
1581 | /* | ||
1582 | * This _could_ be supported by providing a hook for | ||
1583 | * drivers for this function, but at this point it | ||
1584 | * doesn't seem worth bothering. | ||
1585 | */ | ||
1586 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
1587 | return -EOPNOTSUPP; | ||
1588 | 1674 | ||
1675 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { | ||
1676 | ret = drv_set_bitrate_mask(local, sdata, mask); | ||
1677 | if (ret) | ||
1678 | return ret; | ||
1679 | } | ||
1589 | 1680 | ||
1590 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | 1681 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) |
1591 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; | 1682 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
@@ -1784,6 +1875,33 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1784 | 1875 | ||
1785 | *cookie = (unsigned long) skb; | 1876 | *cookie = (unsigned long) skb; |
1786 | 1877 | ||
1878 | if (is_offchan && local->ops->offchannel_tx) { | ||
1879 | int ret; | ||
1880 | |||
1881 | IEEE80211_SKB_CB(skb)->band = chan->band; | ||
1882 | |||
1883 | mutex_lock(&local->mtx); | ||
1884 | |||
1885 | if (local->hw_offchan_tx_cookie) { | ||
1886 | mutex_unlock(&local->mtx); | ||
1887 | return -EBUSY; | ||
1888 | } | ||
1889 | |||
1890 | /* TODO: bitrate control, TX processing? */ | ||
1891 | ret = drv_offchannel_tx(local, skb, chan, channel_type, wait); | ||
1892 | |||
1893 | if (ret == 0) | ||
1894 | local->hw_offchan_tx_cookie = *cookie; | ||
1895 | mutex_unlock(&local->mtx); | ||
1896 | |||
1897 | /* | ||
1898 | * Allow driver to return 1 to indicate it wants to have the | ||
1899 | * frame transmitted with a remain_on_channel + regular TX. | ||
1900 | */ | ||
1901 | if (ret != 1) | ||
1902 | return ret; | ||
1903 | } | ||
1904 | |||
1787 | if (is_offchan && local->ops->remain_on_channel) { | 1905 | if (is_offchan && local->ops->remain_on_channel) { |
1788 | unsigned int duration; | 1906 | unsigned int duration; |
1789 | int ret; | 1907 | int ret; |
@@ -1847,6 +1965,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1847 | 1965 | ||
1848 | wk->type = IEEE80211_WORK_OFFCHANNEL_TX; | 1966 | wk->type = IEEE80211_WORK_OFFCHANNEL_TX; |
1849 | wk->chan = chan; | 1967 | wk->chan = chan; |
1968 | wk->chan_type = channel_type; | ||
1850 | wk->sdata = sdata; | 1969 | wk->sdata = sdata; |
1851 | wk->done = ieee80211_offchan_tx_done; | 1970 | wk->done = ieee80211_offchan_tx_done; |
1852 | wk->offchan_tx.frame = skb; | 1971 | wk->offchan_tx.frame = skb; |
@@ -1869,6 +1988,18 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, | |||
1869 | 1988 | ||
1870 | mutex_lock(&local->mtx); | 1989 | mutex_lock(&local->mtx); |
1871 | 1990 | ||
1991 | if (local->ops->offchannel_tx_cancel_wait && | ||
1992 | local->hw_offchan_tx_cookie == cookie) { | ||
1993 | ret = drv_offchannel_tx_cancel_wait(local); | ||
1994 | |||
1995 | if (!ret) | ||
1996 | local->hw_offchan_tx_cookie = 0; | ||
1997 | |||
1998 | mutex_unlock(&local->mtx); | ||
1999 | |||
2000 | return ret; | ||
2001 | } | ||
2002 | |||
1872 | if (local->ops->cancel_remain_on_channel) { | 2003 | if (local->ops->cancel_remain_on_channel) { |
1873 | cookie ^= 2; | 2004 | cookie ^= 2; |
1874 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | 2005 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); |
@@ -1939,6 +2070,21 @@ static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) | |||
1939 | return drv_get_antenna(local, tx_ant, rx_ant); | 2070 | return drv_get_antenna(local, tx_ant, rx_ant); |
1940 | } | 2071 | } |
1941 | 2072 | ||
2073 | static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) | ||
2074 | { | ||
2075 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
2076 | |||
2077 | return drv_set_ringparam(local, tx, rx); | ||
2078 | } | ||
2079 | |||
2080 | static void ieee80211_get_ringparam(struct wiphy *wiphy, | ||
2081 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
2082 | { | ||
2083 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
2084 | |||
2085 | drv_get_ringparam(local, tx, tx_max, rx, rx_max); | ||
2086 | } | ||
2087 | |||
1942 | struct cfg80211_ops mac80211_config_ops = { | 2088 | struct cfg80211_ops mac80211_config_ops = { |
1943 | .add_virtual_intf = ieee80211_add_iface, | 2089 | .add_virtual_intf = ieee80211_add_iface, |
1944 | .del_virtual_intf = ieee80211_del_iface, | 2090 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1974,6 +2120,8 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1974 | .suspend = ieee80211_suspend, | 2120 | .suspend = ieee80211_suspend, |
1975 | .resume = ieee80211_resume, | 2121 | .resume = ieee80211_resume, |
1976 | .scan = ieee80211_scan, | 2122 | .scan = ieee80211_scan, |
2123 | .sched_scan_start = ieee80211_sched_scan_start, | ||
2124 | .sched_scan_stop = ieee80211_sched_scan_stop, | ||
1977 | .auth = ieee80211_auth, | 2125 | .auth = ieee80211_auth, |
1978 | .assoc = ieee80211_assoc, | 2126 | .assoc = ieee80211_assoc, |
1979 | .deauth = ieee80211_deauth, | 2127 | .deauth = ieee80211_deauth, |
@@ -1996,4 +2144,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1996 | .mgmt_frame_register = ieee80211_mgmt_frame_register, | 2144 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
1997 | .set_antenna = ieee80211_set_antenna, | 2145 | .set_antenna = ieee80211_set_antenna, |
1998 | .get_antenna = ieee80211_get_antenna, | 2146 | .get_antenna = ieee80211_get_antenna, |
2147 | .set_ringparam = ieee80211_set_ringparam, | ||
2148 | .get_ringparam = ieee80211_get_ringparam, | ||
1999 | }; | 2149 | }; |