diff options
Diffstat (limited to 'net/mac80211/main.c')
| -rw-r--r-- | net/mac80211/main.c | 236 |
1 files changed, 181 insertions, 55 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0d2d94881f1f..ded5c3843e06 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
| @@ -17,10 +17,10 @@ | |||
| 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> |
| 23 | #include <linux/inetdevice.h> | ||
| 24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
| 25 | #include <net/cfg80211.h> | 25 | #include <net/cfg80211.h> |
| 26 | 26 | ||
| @@ -32,7 +32,12 @@ | |||
| 32 | #include "led.h" | 32 | #include "led.h" |
| 33 | #include "cfg.h" | 33 | #include "cfg.h" |
| 34 | #include "debugfs.h" | 34 | #include "debugfs.h" |
| 35 | #include "debugfs_netdev.h" | 35 | |
| 36 | |||
| 37 | bool ieee80211_disable_40mhz_24ghz; | ||
| 38 | module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); | ||
| 39 | MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, | ||
| 40 | "Disable 40MHz support in the 2.4GHz band"); | ||
| 36 | 41 | ||
| 37 | void ieee80211_configure_filter(struct ieee80211_local *local) | 42 | void ieee80211_configure_filter(struct ieee80211_local *local) |
| 38 | { | 43 | { |
| @@ -67,7 +72,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local) | |||
| 67 | spin_lock_bh(&local->filter_lock); | 72 | spin_lock_bh(&local->filter_lock); |
| 68 | changed_flags = local->filter_flags ^ new_flags; | 73 | changed_flags = local->filter_flags ^ new_flags; |
| 69 | 74 | ||
| 70 | mc = drv_prepare_multicast(local, local->mc_count, local->mc_list); | 75 | mc = drv_prepare_multicast(local, &local->mc_list); |
| 71 | spin_unlock_bh(&local->filter_lock); | 76 | spin_unlock_bh(&local->filter_lock); |
| 72 | 77 | ||
| 73 | /* be a bit nasty */ | 78 | /* be a bit nasty */ |
| @@ -102,9 +107,15 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
| 102 | if (scan_chan) { | 107 | if (scan_chan) { |
| 103 | chan = scan_chan; | 108 | chan = scan_chan; |
| 104 | channel_type = NL80211_CHAN_NO_HT; | 109 | channel_type = NL80211_CHAN_NO_HT; |
| 110 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | ||
| 111 | } else if (local->tmp_channel) { | ||
| 112 | chan = scan_chan = local->tmp_channel; | ||
| 113 | channel_type = local->tmp_channel_type; | ||
| 114 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | ||
| 105 | } else { | 115 | } else { |
| 106 | chan = local->oper_channel; | 116 | chan = local->oper_channel; |
| 107 | channel_type = local->oper_channel_type; | 117 | channel_type = local->_oper_channel_type; |
| 118 | local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; | ||
| 108 | } | 119 | } |
| 109 | 120 | ||
| 110 | if (chan != local->hw.conf.channel || | 121 | if (chan != local->hw.conf.channel || |
| @@ -114,6 +125,18 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
| 114 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; | 125 | changed |= IEEE80211_CONF_CHANGE_CHANNEL; |
| 115 | } | 126 | } |
| 116 | 127 | ||
| 128 | if (!conf_is_ht(&local->hw.conf)) { | ||
| 129 | /* | ||
| 130 | * mac80211.h documents that this is only valid | ||
| 131 | * when the channel is set to an HT type, and | ||
| 132 | * that otherwise STATIC is used. | ||
| 133 | */ | ||
| 134 | local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; | ||
| 135 | } else if (local->hw.conf.smps_mode != local->smps_mode) { | ||
| 136 | local->hw.conf.smps_mode = local->smps_mode; | ||
| 137 | changed |= IEEE80211_CONF_CHANGE_SMPS; | ||
| 138 | } | ||
| 139 | |||
| 117 | if (scan_chan) | 140 | if (scan_chan) |
| 118 | power = chan->max_power; | 141 | power = chan->max_power; |
| 119 | else | 142 | else |
| @@ -173,7 +196,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 173 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 196 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
| 174 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 197 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
| 175 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 198 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
| 176 | sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; | 199 | sdata->vif.bss_conf.bssid = sdata->vif.addr; |
| 177 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 200 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| 178 | sdata->vif.bss_conf.bssid = zero; | 201 | sdata->vif.bss_conf.bssid = zero; |
| 179 | } else { | 202 | } else { |
| @@ -195,7 +218,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 195 | } | 218 | } |
| 196 | 219 | ||
| 197 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 220 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
| 198 | if (local->quiescing || !netif_running(sdata->dev) || | 221 | if (local->quiescing || !ieee80211_sdata_running(sdata) || |
| 199 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { | 222 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { |
| 200 | sdata->vif.bss_conf.enable_beacon = false; | 223 | sdata->vif.bss_conf.enable_beacon = false; |
| 201 | } else { | 224 | } else { |
| @@ -206,11 +229,11 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 206 | switch (sdata->vif.type) { | 229 | switch (sdata->vif.type) { |
| 207 | case NL80211_IFTYPE_AP: | 230 | case NL80211_IFTYPE_AP: |
| 208 | sdata->vif.bss_conf.enable_beacon = | 231 | sdata->vif.bss_conf.enable_beacon = |
| 209 | !!rcu_dereference(sdata->u.ap.beacon); | 232 | !!sdata->u.ap.beacon; |
| 210 | break; | 233 | break; |
| 211 | case NL80211_IFTYPE_ADHOC: | 234 | case NL80211_IFTYPE_ADHOC: |
| 212 | sdata->vif.bss_conf.enable_beacon = | 235 | sdata->vif.bss_conf.enable_beacon = |
| 213 | !!rcu_dereference(sdata->u.ibss.presp); | 236 | !!sdata->u.ibss.presp; |
| 214 | break; | 237 | break; |
| 215 | case NL80211_IFTYPE_MESH_POINT: | 238 | case NL80211_IFTYPE_MESH_POINT: |
| 216 | sdata->vif.bss_conf.enable_beacon = true; | 239 | sdata->vif.bss_conf.enable_beacon = true; |
| @@ -223,8 +246,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
| 223 | } | 246 | } |
| 224 | } | 247 | } |
| 225 | 248 | ||
| 226 | drv_bss_info_changed(local, &sdata->vif, | 249 | drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); |
| 227 | &sdata->vif.bss_conf, changed); | ||
| 228 | } | 250 | } |
| 229 | 251 | ||
| 230 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) | 252 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) |
| @@ -241,7 +263,6 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
| 241 | { | 263 | { |
| 242 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 264 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
| 243 | struct sk_buff *skb; | 265 | struct sk_buff *skb; |
| 244 | struct ieee80211_ra_tid *ra_tid; | ||
| 245 | 266 | ||
| 246 | while ((skb = skb_dequeue(&local->skb_queue)) || | 267 | while ((skb = skb_dequeue(&local->skb_queue)) || |
| 247 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { | 268 | (skb = skb_dequeue(&local->skb_queue_unreliable))) { |
| @@ -256,18 +277,6 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
| 256 | skb->pkt_type = 0; | 277 | skb->pkt_type = 0; |
| 257 | ieee80211_tx_status(local_to_hw(local), skb); | 278 | ieee80211_tx_status(local_to_hw(local), skb); |
| 258 | break; | 279 | break; |
| 259 | case IEEE80211_DELBA_MSG: | ||
| 260 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
| 261 | ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra, | ||
| 262 | ra_tid->tid); | ||
| 263 | dev_kfree_skb(skb); | ||
| 264 | break; | ||
| 265 | case IEEE80211_ADDBA_MSG: | ||
| 266 | ra_tid = (struct ieee80211_ra_tid *) &skb->cb; | ||
| 267 | ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra, | ||
| 268 | ra_tid->tid); | ||
| 269 | dev_kfree_skb(skb); | ||
| 270 | break ; | ||
| 271 | default: | 280 | default: |
| 272 | WARN(1, "mac80211: Packet is of unknown type %d\n", | 281 | WARN(1, "mac80211: Packet is of unknown type %d\n", |
| 273 | skb->pkt_type); | 282 | skb->pkt_type); |
| @@ -291,6 +300,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
| 291 | { | 300 | { |
| 292 | struct ieee80211_local *local = hw_to_local(hw); | 301 | struct ieee80211_local *local = hw_to_local(hw); |
| 293 | 302 | ||
| 303 | trace_api_restart_hw(local); | ||
| 304 | |||
| 294 | /* use this reason, __ieee80211_resume will unblock it */ | 305 | /* use this reason, __ieee80211_resume will unblock it */ |
| 295 | ieee80211_stop_queues_by_reason(hw, | 306 | ieee80211_stop_queues_by_reason(hw, |
| 296 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 307 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
| @@ -299,6 +310,86 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) | |||
| 299 | } | 310 | } |
| 300 | EXPORT_SYMBOL(ieee80211_restart_hw); | 311 | EXPORT_SYMBOL(ieee80211_restart_hw); |
| 301 | 312 | ||
| 313 | static void ieee80211_recalc_smps_work(struct work_struct *work) | ||
| 314 | { | ||
| 315 | struct ieee80211_local *local = | ||
| 316 | container_of(work, struct ieee80211_local, recalc_smps); | ||
| 317 | |||
| 318 | mutex_lock(&local->iflist_mtx); | ||
| 319 | ieee80211_recalc_smps(local, NULL); | ||
| 320 | mutex_unlock(&local->iflist_mtx); | ||
| 321 | } | ||
| 322 | |||
| 323 | #ifdef CONFIG_INET | ||
| 324 | static int ieee80211_ifa_changed(struct notifier_block *nb, | ||
| 325 | unsigned long data, void *arg) | ||
| 326 | { | ||
| 327 | struct in_ifaddr *ifa = arg; | ||
| 328 | struct ieee80211_local *local = | ||
| 329 | container_of(nb, struct ieee80211_local, | ||
| 330 | ifa_notifier); | ||
| 331 | struct net_device *ndev = ifa->ifa_dev->dev; | ||
| 332 | struct wireless_dev *wdev = ndev->ieee80211_ptr; | ||
| 333 | struct in_device *idev; | ||
| 334 | struct ieee80211_sub_if_data *sdata; | ||
| 335 | struct ieee80211_bss_conf *bss_conf; | ||
| 336 | struct ieee80211_if_managed *ifmgd; | ||
| 337 | int c = 0; | ||
| 338 | |||
| 339 | if (!netif_running(ndev)) | ||
| 340 | return NOTIFY_DONE; | ||
| 341 | |||
| 342 | /* Make sure it's our interface that got changed */ | ||
| 343 | if (!wdev) | ||
| 344 | return NOTIFY_DONE; | ||
| 345 | |||
| 346 | if (wdev->wiphy != local->hw.wiphy) | ||
| 347 | return NOTIFY_DONE; | ||
| 348 | |||
| 349 | sdata = IEEE80211_DEV_TO_SUB_IF(ndev); | ||
| 350 | bss_conf = &sdata->vif.bss_conf; | ||
| 351 | |||
| 352 | /* ARP filtering is only supported in managed mode */ | ||
| 353 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
| 354 | return NOTIFY_DONE; | ||
| 355 | |||
| 356 | idev = sdata->dev->ip_ptr; | ||
| 357 | if (!idev) | ||
| 358 | return NOTIFY_DONE; | ||
| 359 | |||
| 360 | ifmgd = &sdata->u.mgd; | ||
| 361 | mutex_lock(&ifmgd->mtx); | ||
| 362 | |||
| 363 | /* Copy the addresses to the bss_conf list */ | ||
| 364 | ifa = idev->ifa_list; | ||
| 365 | while (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN && ifa) { | ||
| 366 | bss_conf->arp_addr_list[c] = ifa->ifa_address; | ||
| 367 | ifa = ifa->ifa_next; | ||
| 368 | c++; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* If not all addresses fit the list, disable filtering */ | ||
| 372 | if (ifa) { | ||
| 373 | sdata->arp_filter_state = false; | ||
| 374 | c = 0; | ||
| 375 | } else { | ||
| 376 | sdata->arp_filter_state = true; | ||
| 377 | } | ||
| 378 | bss_conf->arp_addr_cnt = c; | ||
| 379 | |||
| 380 | /* Configure driver only if associated */ | ||
| 381 | if (ifmgd->associated) { | ||
| 382 | bss_conf->arp_filter_enabled = sdata->arp_filter_state; | ||
| 383 | ieee80211_bss_info_change_notify(sdata, | ||
| 384 | BSS_CHANGED_ARP_FILTER); | ||
| 385 | } | ||
| 386 | |||
| 387 | mutex_unlock(&ifmgd->mtx); | ||
| 388 | |||
| 389 | return NOTIFY_DONE; | ||
| 390 | } | ||
| 391 | #endif | ||
| 392 | |||
| 302 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 393 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
| 303 | const struct ieee80211_ops *ops) | 394 | const struct ieee80211_ops *ops) |
| 304 | { | 395 | { |
| @@ -333,9 +424,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 333 | WIPHY_FLAG_4ADDR_STATION; | 424 | WIPHY_FLAG_4ADDR_STATION; |
| 334 | wiphy->privid = mac80211_wiphy_privid; | 425 | wiphy->privid = mac80211_wiphy_privid; |
| 335 | 426 | ||
| 336 | /* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | 427 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss); |
| 337 | wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | ||
| 338 | sizeof(struct cfg80211_bss); | ||
| 339 | 428 | ||
| 340 | local = wiphy_priv(wiphy); | 429 | local = wiphy_priv(wiphy); |
| 341 | 430 | ||
| @@ -358,20 +447,29 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 358 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 447 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
| 359 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 448 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
| 360 | local->user_power_level = -1; | 449 | local->user_power_level = -1; |
| 450 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; | ||
| 451 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; | ||
| 361 | 452 | ||
| 362 | INIT_LIST_HEAD(&local->interfaces); | 453 | INIT_LIST_HEAD(&local->interfaces); |
| 454 | |||
| 455 | __hw_addr_init(&local->mc_list); | ||
| 456 | |||
| 363 | mutex_init(&local->iflist_mtx); | 457 | mutex_init(&local->iflist_mtx); |
| 364 | mutex_init(&local->scan_mtx); | 458 | mutex_init(&local->scan_mtx); |
| 365 | 459 | ||
| 366 | spin_lock_init(&local->key_lock); | 460 | mutex_init(&local->key_mtx); |
| 367 | spin_lock_init(&local->filter_lock); | 461 | spin_lock_init(&local->filter_lock); |
| 368 | spin_lock_init(&local->queue_stop_reason_lock); | 462 | spin_lock_init(&local->queue_stop_reason_lock); |
| 369 | 463 | ||
| 370 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | 464 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); |
| 371 | 465 | ||
| 466 | ieee80211_work_init(local); | ||
| 467 | |||
| 372 | INIT_WORK(&local->restart_work, ieee80211_restart_work); | 468 | INIT_WORK(&local->restart_work, ieee80211_restart_work); |
| 373 | 469 | ||
| 374 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | 470 | INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); |
| 471 | INIT_WORK(&local->recalc_smps, ieee80211_recalc_smps_work); | ||
| 472 | local->smps_mode = IEEE80211_SMPS_OFF; | ||
| 375 | 473 | ||
| 376 | INIT_WORK(&local->dynamic_ps_enable_work, | 474 | INIT_WORK(&local->dynamic_ps_enable_work, |
| 377 | ieee80211_dynamic_ps_enable_work); | 475 | ieee80211_dynamic_ps_enable_work); |
| @@ -382,8 +480,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 382 | 480 | ||
| 383 | sta_info_init(local); | 481 | sta_info_init(local); |
| 384 | 482 | ||
| 385 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) | 483 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { |
| 386 | skb_queue_head_init(&local->pending[i]); | 484 | skb_queue_head_init(&local->pending[i]); |
| 485 | atomic_set(&local->agg_queue_stop[i], 0); | ||
| 486 | } | ||
| 387 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 487 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
| 388 | (unsigned long)local); | 488 | (unsigned long)local); |
| 389 | 489 | ||
| @@ -394,8 +494,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
| 394 | skb_queue_head_init(&local->skb_queue); | 494 | skb_queue_head_init(&local->skb_queue); |
| 395 | skb_queue_head_init(&local->skb_queue_unreliable); | 495 | skb_queue_head_init(&local->skb_queue_unreliable); |
| 396 | 496 | ||
| 397 | spin_lock_init(&local->ampdu_lock); | ||
| 398 | |||
| 399 | return local_to_hw(local); | 497 | return local_to_hw(local); |
| 400 | } | 498 | } |
| 401 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 499 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
| @@ -405,7 +503,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 405 | struct ieee80211_local *local = hw_to_local(hw); | 503 | struct ieee80211_local *local = hw_to_local(hw); |
| 406 | int result; | 504 | int result; |
| 407 | enum ieee80211_band band; | 505 | enum ieee80211_band band; |
| 408 | int channels, i, j, max_bitrates; | 506 | int channels, max_bitrates; |
| 409 | bool supp_ht; | 507 | bool supp_ht; |
| 410 | static const u32 cipher_suites[] = { | 508 | static const u32 cipher_suites[] = { |
| 411 | WLAN_CIPHER_SUITE_WEP40, | 509 | WLAN_CIPHER_SUITE_WEP40, |
| @@ -461,6 +559,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 461 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 559 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
| 462 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | 560 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; |
| 463 | 561 | ||
| 562 | WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | ||
| 563 | && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), | ||
| 564 | "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); | ||
| 565 | |||
| 464 | /* | 566 | /* |
| 465 | * Calculate scan IE length -- we need this to alloc | 567 | * Calculate scan IE length -- we need this to alloc |
| 466 | * memory and to subtract from the driver limit. It | 568 | * memory and to subtract from the driver limit. It |
| @@ -522,21 +624,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 522 | 624 | ||
| 523 | debugfs_hw_add(local); | 625 | debugfs_hw_add(local); |
| 524 | 626 | ||
| 627 | /* | ||
| 628 | * if the driver doesn't specify a max listen interval we | ||
| 629 | * use 5 which should be a safe default | ||
| 630 | */ | ||
| 525 | if (local->hw.max_listen_interval == 0) | 631 | if (local->hw.max_listen_interval == 0) |
| 526 | local->hw.max_listen_interval = 1; | 632 | local->hw.max_listen_interval = 5; |
| 527 | 633 | ||
| 528 | local->hw.conf.listen_interval = local->hw.max_listen_interval; | 634 | local->hw.conf.listen_interval = local->hw.max_listen_interval; |
| 529 | 635 | ||
| 636 | local->dynamic_ps_forced_timeout = -1; | ||
| 637 | |||
| 530 | result = sta_info_start(local); | 638 | result = sta_info_start(local); |
| 531 | if (result < 0) | 639 | if (result < 0) |
| 532 | goto fail_sta_info; | 640 | goto fail_sta_info; |
| 533 | 641 | ||
| 534 | result = ieee80211_wep_init(local); | 642 | result = ieee80211_wep_init(local); |
| 535 | if (result < 0) { | 643 | if (result < 0) |
| 536 | printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", | 644 | printk(KERN_DEBUG "%s: Failed to initialize wep: %d\n", |
| 537 | wiphy_name(local->hw.wiphy), result); | 645 | wiphy_name(local->hw.wiphy), result); |
| 538 | goto fail_wep; | ||
| 539 | } | ||
| 540 | 646 | ||
| 541 | rtnl_lock(); | 647 | rtnl_lock(); |
| 542 | 648 | ||
| @@ -561,40 +667,36 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
| 561 | 667 | ||
| 562 | ieee80211_led_init(local); | 668 | ieee80211_led_init(local); |
| 563 | 669 | ||
| 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 = | 670 | local->network_latency_notifier.notifier_call = |
| 580 | ieee80211_max_network_latency; | 671 | ieee80211_max_network_latency; |
| 581 | result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, | 672 | result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, |
| 582 | &local->network_latency_notifier); | 673 | &local->network_latency_notifier); |
| 583 | |||
| 584 | if (result) { | 674 | if (result) { |
| 585 | rtnl_lock(); | 675 | rtnl_lock(); |
| 586 | goto fail_pm_qos; | 676 | goto fail_pm_qos; |
| 587 | } | 677 | } |
| 588 | 678 | ||
| 679 | #ifdef CONFIG_INET | ||
| 680 | local->ifa_notifier.notifier_call = ieee80211_ifa_changed; | ||
| 681 | result = register_inetaddr_notifier(&local->ifa_notifier); | ||
| 682 | if (result) | ||
| 683 | goto fail_ifa; | ||
| 684 | #endif | ||
| 685 | |||
| 589 | return 0; | 686 | return 0; |
| 590 | 687 | ||
| 688 | #ifdef CONFIG_INET | ||
| 689 | fail_ifa: | ||
| 690 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, | ||
| 691 | &local->network_latency_notifier); | ||
| 692 | rtnl_lock(); | ||
| 693 | #endif | ||
| 591 | fail_pm_qos: | 694 | fail_pm_qos: |
| 592 | ieee80211_led_exit(local); | 695 | ieee80211_led_exit(local); |
| 593 | ieee80211_remove_interfaces(local); | 696 | ieee80211_remove_interfaces(local); |
| 594 | fail_rate: | 697 | fail_rate: |
| 595 | rtnl_unlock(); | 698 | rtnl_unlock(); |
| 596 | ieee80211_wep_free(local); | 699 | ieee80211_wep_free(local); |
| 597 | fail_wep: | ||
| 598 | sta_info_stop(local); | 700 | sta_info_stop(local); |
| 599 | fail_sta_info: | 701 | fail_sta_info: |
| 600 | destroy_workqueue(local->workqueue); | 702 | destroy_workqueue(local->workqueue); |
| @@ -615,6 +717,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
| 615 | 717 | ||
| 616 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, | 718 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, |
| 617 | &local->network_latency_notifier); | 719 | &local->network_latency_notifier); |
| 720 | #ifdef CONFIG_INET | ||
| 721 | unregister_inetaddr_notifier(&local->ifa_notifier); | ||
| 722 | #endif | ||
| 618 | 723 | ||
| 619 | rtnl_lock(); | 724 | rtnl_lock(); |
| 620 | 725 | ||
| @@ -627,6 +732,12 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) | |||
| 627 | 732 | ||
| 628 | rtnl_unlock(); | 733 | rtnl_unlock(); |
| 629 | 734 | ||
| 735 | /* | ||
| 736 | * Now all work items will be gone, but the | ||
| 737 | * timer might still be armed, so delete it | ||
| 738 | */ | ||
| 739 | del_timer_sync(&local->work_timer); | ||
| 740 | |||
| 630 | cancel_work_sync(&local->reconfig_filter); | 741 | cancel_work_sync(&local->reconfig_filter); |
| 631 | 742 | ||
| 632 | ieee80211_clear_tx_pending(local); | 743 | ieee80211_clear_tx_pending(local); |
| @@ -672,18 +783,33 @@ static int __init ieee80211_init(void) | |||
| 672 | if (ret) | 783 | if (ret) |
| 673 | return ret; | 784 | return ret; |
| 674 | 785 | ||
| 786 | ret = rc80211_minstrel_ht_init(); | ||
| 787 | if (ret) | ||
| 788 | goto err_minstrel; | ||
| 789 | |||
| 675 | ret = rc80211_pid_init(); | 790 | ret = rc80211_pid_init(); |
| 676 | if (ret) | 791 | if (ret) |
| 677 | return ret; | 792 | goto err_pid; |
| 678 | 793 | ||
| 679 | ieee80211_debugfs_netdev_init(); | 794 | ret = ieee80211_iface_init(); |
| 795 | if (ret) | ||
| 796 | goto err_netdev; | ||
| 680 | 797 | ||
| 681 | return 0; | 798 | return 0; |
| 799 | err_netdev: | ||
| 800 | rc80211_pid_exit(); | ||
| 801 | err_pid: | ||
| 802 | rc80211_minstrel_ht_exit(); | ||
| 803 | err_minstrel: | ||
| 804 | rc80211_minstrel_exit(); | ||
| 805 | |||
| 806 | return ret; | ||
| 682 | } | 807 | } |
| 683 | 808 | ||
| 684 | static void __exit ieee80211_exit(void) | 809 | static void __exit ieee80211_exit(void) |
| 685 | { | 810 | { |
| 686 | rc80211_pid_exit(); | 811 | rc80211_pid_exit(); |
| 812 | rc80211_minstrel_ht_exit(); | ||
| 687 | rc80211_minstrel_exit(); | 813 | rc80211_minstrel_exit(); |
| 688 | 814 | ||
| 689 | /* | 815 | /* |
| @@ -695,7 +821,7 @@ static void __exit ieee80211_exit(void) | |||
| 695 | if (mesh_allocated) | 821 | if (mesh_allocated) |
| 696 | ieee80211s_stop(); | 822 | ieee80211s_stop(); |
| 697 | 823 | ||
| 698 | ieee80211_debugfs_netdev_exit(); | 824 | ieee80211_iface_exit(); |
| 699 | } | 825 | } |
| 700 | 826 | ||
| 701 | 827 | ||
