diff options
Diffstat (limited to 'net/mac80211/main.c')
| -rw-r--r-- | net/mac80211/main.c | 106 |
1 files changed, 73 insertions, 33 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0d2d94881f1f..22a384dfab65 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -17,7 +17,6 @@ | |||
| 17 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
| 18 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
| 19 | #include <linux/if_arp.h> | 19 | #include <linux/if_arp.h> |
| 20 | #include <linux/wireless.h> | ||
| 21 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
| 22 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
| 23 | #include <linux/pm_qos_params.h> | 22 | #include <linux/pm_qos_params.h> |
| @@ -32,7 +31,12 @@ | |||
| 32 | #include "led.h" | 31 | #include "led.h" |
| 33 | #include "cfg.h" | 32 | #include "cfg.h" |
| 34 | #include "debugfs.h" | 33 | #include "debugfs.h" |
| 35 | #include "debugfs_netdev.h" | 34 | |
| 35 | |||
| 36 | bool ieee80211_disable_40mhz_24ghz; | ||
| 37 | module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); | ||
| 38 | MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, | ||
| 39 | "Disable 40MHz support in the 2.4GHz band"); | ||
| 36 | 40 | ||
| 37 | void ieee80211_configure_filter(struct ieee80211_local *local) | 41 | void ieee80211_configure_filter(struct ieee80211_local *local) |
| 38 | { | 42 | { |
| @@ -67,7 +71,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
| 67 | spin_lock_bh(&local->filter_lock); | 71 | spin_lock_bh(&local->filter_lock); |
| 68 | changed_flags = local->filter_flags ^ new_flags; | 72 | changed_flags = local->filter_flags ^ new_flags; |
| 69 | 73 | ||
| 70 | mc = drv_prepare_multicast(local, local->mc_count, local->mc_list); | 74 | mc = drv_prepare_multicast(local, &local->mc_list); |
| 71 | spin_unlock_bh(&local->filter_lock); | 75 | spin_unlock_bh(&local->filter_lock); |
| 72 | 76 | ||
| 73 | /* be a bit nasty */ | 77 | /* be a bit nasty */ |
| @@ -102,9 +106,12 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
| 102 | if (scan_chan) { | 106 | if (scan_chan) { |
| 103 | chan = scan_chan; | 107 | chan = scan_chan; |
| 104 | channel_type = NL80211_CHAN_NO_HT; | 108 | channel_type = NL80211_CHAN_NO_HT; |
| 109 | } else if (local->tmp_channel) { | ||
| 110 | chan = scan_chan = local->tmp_channel; | ||
| 111 | channel_type = local->tmp_channel_type; | ||
| 105 | } else { | 112 | } else { |
| 106 | chan = local->oper_channel; | 113 | chan = local->oper_channel; |
| 107 | channel_type = local->oper_channel_type; | 114 | channel_type = local->_oper_channel_type; |
| 108 | } | 115 | } |
| 109 | 116 | ||
| 110 | if (chan != local->hw.conf.channel || | 117 | if (chan != local->hw.conf.channel || |
| @@ -114,6 +121,18 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
| 114 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 121 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
| 115 | } | 122 | } |
| 116 | 123 | ||
| 124 | if (!conf_is_ht(&local->hw.conf)) { | ||
| 125 | /* | ||
| 126 | * mac80211.h documents that this is only valid | ||
| 127 | * when the channel is set to an HT type, and | ||
| 128 | * that otherwise STATIC is used. | ||
| 129 | */ | ||
| 130 | local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; | ||
| 131 | } else if (local->hw.conf.smps_mode != local->smps_mode) { | ||
| 132 | local->hw.conf.smps_mode = local->smps_mode; | ||
| 133 | changed |= IEEE80211_CONF_CHANGE_SMPS; | ||
| 134 | } | ||
| 135 | |||
| 117 | if (scan_chan) | 136 | if (scan_chan) |
| 118 | power = chan->max_power; | 137 | power = chan->max_power; |
| 119 | else | 138 | else |
| @@ -173,7 +192,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 173 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 192 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
| 174 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 193 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
| 175 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 194 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
| 176 | sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; | 195 | sdata->vif.bss_conf.bssid = sdata->vif.addr; |
| 177 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 196 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 178 | sdata->vif.bss_conf.bssid = zero; | 197 | sdata->vif.bss_conf.bssid = zero; |
| 179 | } else { | 198 | } else { |
| @@ -195,7 +214,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 195 | } | 214 | } |
| 196 | 215 | ||
| 197 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 216 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
| 198 | if (local->quiescing || !netif_running(sdata->dev) || | 217 | if (local->quiescing || !ieee80211_sdata_running(sdata) || |
| 199 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { | 218 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { |
| 200 | sdata->vif.bss_conf.enable_beacon = false; | 219 | sdata->vif.bss_conf.enable_beacon = false; |
| 201 | } else { | 220 | } else { |
| @@ -206,11 +225,11 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 206 | switch (sdata->vif.type) { | 225 | switch (sdata->vif.type) { |
| 207 | case NL80211_IFTYPE_AP: | 226 | case NL80211_IFTYPE_AP: |
| 208 | sdata->vif.bss_conf.enable_beacon = | 227 | sdata->vif.bss_conf.enable_beacon = |
| 209 | !!rcu_dereference(sdata->u.ap.beacon); | 228 | !!sdata->u.ap.beacon; |
| 210 | break; | 229 | break; |
| 211 | case NL80211_IFTYPE_ADHOC: | 230 | case NL80211_IFTYPE_ADHOC: |
| 212 | sdata->vif.bss_conf.enable_beacon = | 231 | sdata->vif.bss_conf.enable_beacon = |
| 213 | !!rcu_dereference(sdata->u.ibss.presp); | 232 | !!sdata->u.ibss.presp; |
| 214 | break; | 233 | break; |
| 215 | case NL80211_IFTYPE_MESH_POINT: | 234 | case NL80211_IFTYPE_MESH_POINT: |
| 216 | sdata->vif.bss_conf.enable_beacon = true; | 235 | sdata->vif.bss_conf.enable_beacon = true; |
| @@ -223,8 +242,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 223 | } | 242 | } |
| 224 | } | 243 | } |
| 225 | 244 | ||
| 226 | drv_bss_info_changed(local, &sdata->vif, | 245 | drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); |
| 227 | &sdata->vif.bss_conf, changed); | ||
| 228 | } | 246 | } |
| 229 | 247 | ||
| 230 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 248 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
| @@ -291,6 +309,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
| 291 | { | 309 | { |
| 292 | struct ieee80211_local *local = hw_to_local(hw); | 310 | struct ieee80211_local *local = hw_to_local(hw); |
| 293 | 311 | ||
| 312 | trace_api_restart_hw(local); | ||
| 313 | |||
| 294 | /* use this reason, __ieee80211_resume will unblock it */ | 314 | /* use this reason, __ieee80211_resume will unblock it */ |
| 295 | ieee80211_stop_queues_by_reason(hw, | 315 | ieee80211_stop_queues_by_reason(hw, |
| 296 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 316 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
| @@ -299,6 +319,16 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
| 299 | } | 319 | } |
| 300 | EXPORT_SYMBOL(ieee80211_restart_hw); | 320 | EXPORT_SYMBOL(ieee80211_restart_hw); |
| 301 | 321 | ||
| 322 | static void ieee80211_recalc_smps_work(struct work_struct *work) | ||
| 323 | { | ||
| 324 | struct ieee80211_local *local = | ||
| 325 | container_of(work, struct ieee80211_local, recalc_smps); | ||
| 326 | |||
| 327 | mutex_lock(&local->iflist_mtx); | ||
| 328 | ieee80211_recalc_smps(local, NULL); | ||
| 329 | mutex_unlock(&local->iflist_mtx); | ||
| 330 | } | ||
| 331 | |||
| 302 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 332 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
| 303 | const struct ieee80211_ops *ops) | 333 | const struct ieee80211_ops *ops) |
| 304 | { | 334 | { |
| @@ -333,9 +363,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 333 | WIPHY_FLAG_4ADDR_STATION; | 363 | WIPHY_FLAG_4ADDR_STATION; |
| 334 | wiphy->privid = mac80211_wiphy_privid; | 364 | wiphy->privid = mac80211_wiphy_privid; |
| 335 | 365 | ||
| 336 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | 366 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss); |
| 337 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | ||
| 338 | sizeof(struct cfg80211_bss); | ||
| 339 | 367 | ||
| 340 | local = wiphy_priv(wiphy); | 368 | local = wiphy_priv(wiphy); |
| 341 | 369 | ||
| @@ -358,8 +386,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 358 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 386 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
| 359 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 387 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
| 360 | local->user_power_level = -1; | 388 | local->user_power_level = -1; |
| 389 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; | ||
| 390 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; | ||
| 361 | 391 | ||
| 362 | INIT_LIST_HEAD(&local->interfaces); | 392 | INIT_LIST_HEAD(&local->interfaces); |
| 393 | |||
| 394 | __hw_addr_init(&local->mc_list); | ||
| 395 | |||
| 363 | mutex_init(&local->iflist_mtx); | 396 | mutex_init(&local->iflist_mtx); |
| 364 | mutex_init(&local->scan_mtx); | 397 | mutex_init(&local->scan_mtx); |
| 365 | 398 | ||
| @@ -369,9 +402,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 369 | 402 | ||
| 370 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 403 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
| 371 | 404 | ||
| 405 | ieee80211_work_init(local); | ||
| 406 | |||
| 372 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 407 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
| 373 | 408 | ||
| 374 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | 409 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); |
| 410 | INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); | ||
| 411 | local->smps_mode = IEEE80211_SMPS_OFF; | ||
| 375 | 412 | ||
| 376 | INIT_WORK(&local->dynamic_ps_enable_work, | 413 | INIT_WORK(&local->dynamic_ps_enable_work, |
| 377 | ieee80211_dynamic_ps_enable_work); | 414 | ieee80211_dynamic_ps_enable_work); |
| @@ -405,7 +442,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 405 | struct ieee80211_local *local = hw_to_local(hw); | 442 | struct ieee80211_local *local = hw_to_local(hw); |
| 406 | int result; | 443 | int result; |
| 407 | enum ieee80211_band band; | 444 | enum ieee80211_band band; |
| 408 | int channels, i, j, max_bitrates; | 445 | int channels, max_bitrates; |
| 409 | bool supp_ht; | 446 | bool supp_ht; |
| 410 | static const u32 cipher_suites[] = { | 447 | static const u32 cipher_suites[] = { |
| 411 | WLAN_CIPHER_SUITE_WEP40, | 448 | WLAN_CIPHER_SUITE_WEP40, |
| @@ -461,6 +498,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 461 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 498 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
| 462 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | 499 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; |
| 463 | 500 | ||
| 501 | WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | ||
| 502 | && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), | ||
| 503 | "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); | ||
| 504 | |||
| 464 | /* | 505 | /* |
| 465 | * Calculate scan IE length -- we need this to alloc | 506 | * Calculate scan IE length -- we need this to alloc |
| 466 | * memory and to subtract from the driver limit. It | 507 | * memory and to subtract from the driver limit. It |
| @@ -522,11 +563,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 522 | 563 | ||
| 523 | debugfs_hw_add(local); | 564 | debugfs_hw_add(local); |
| 524 | 565 | ||
| 566 | /* | ||
| 567 | * if the driver doesn't specify a max listen interval we | ||
| 568 | * use 5 which should be a safe default | ||
| 569 | */ | ||
| 525 | if (local->hw.max_listen_interval == 0) | 570 | if (local->hw.max_listen_interval == 0) |
| 526 | local->hw.max_listen_interval = 1; | 571 | local->hw.max_listen_interval = 5; |
| 527 | 572 | ||
| 528 | local->hw.conf.listen_interval = local->hw.max_listen_interval; | 573 | local->hw.conf.listen_interval = local->hw.max_listen_interval; |
| 529 | 574 | ||
| 575 | local->hw.conf.dynamic_ps_forced_timeout = -1; | ||
| 576 | |||
| 530 | result = sta_info_start(local); | 577 | result = sta_info_start(local); |
| 531 | if (result < 0) | 578 | if (result < 0) |
| 532 | goto fail_sta_info; | 579 | goto fail_sta_info; |
| @@ -561,21 +608,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 561 | 608 | ||
| 562 | ieee80211_led_init(local); | 609 | ieee80211_led_init(local); |
| 563 | 610 | ||
| 564 | /* alloc internal scan request */ | ||
| 565 | i = 0; | ||
| 566 | local->int_scan_req->ssids = &local->scan_ssid; | ||
| 567 | local->int_scan_req->n_ssids = 1; | ||
| 568 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
| 569 | if (!hw->wiphy->bands[band]) | ||
| 570 | continue; | ||
| 571 | for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) { | ||
| 572 | local->int_scan_req->channels[i] = | ||
| 573 | &hw->wiphy->bands[band]->channels[j]; | ||
| 574 | i++; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | local->int_scan_req->n_channels = i; | ||
| 578 | |||
| 579 | local->network_latency_notifier.notifier_call = | 611 | local->network_latency_notifier.notifier_call = |
| 580 | ieee80211_max_network_latency; | 612 | ieee80211_max_network_latency; |
| 581 | result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, | 613 | result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, |
| @@ -674,11 +706,19 @@ static int __init ieee80211_init(void) | |||
| 674 | 706 | ||
| 675 | ret = rc80211_pid_init(); | 707 | ret = rc80211_pid_init(); |
| 676 | if (ret) | 708 | if (ret) |
| 677 | return ret; | 709 | goto err_pid; |
| 678 | 710 | ||
| 679 | ieee80211_debugfs_netdev_init(); | 711 | ret = ieee80211_iface_init(); |
| 712 | if (ret) | ||
| 713 | goto err_netdev; | ||
| 680 | 714 | ||
| 681 | return 0; | 715 | return 0; |
| 716 | err_netdev: | ||
| 717 | rc80211_pid_exit(); | ||
| 718 | err_pid: | ||
| 719 | rc80211_minstrel_exit(); | ||
| 720 | |||
| 721 | return ret; | ||
| 682 | } | 722 | } |
| 683 | 723 | ||
| 684 | static void __exit ieee80211_exit(void) | 724 | static void __exit ieee80211_exit(void) |
| @@ -695,7 +735,7 @@ static void __exit ieee80211_exit(void) | |||
| 695 | if (mesh_allocated) | 735 | if (mesh_allocated) |
| 696 | ieee80211s_stop(); | 736 | ieee80211s_stop(); |
| 697 | 737 | ||
| 698 | ieee80211_debugfs_netdev_exit(); | 738 | ieee80211_iface_exit(); |
| 699 | } | 739 | } |
| 700 | 740 | ||
| 701 | 741 | ||
