diff options
author | David S. Miller <davem@davemloft.net> | 2010-02-14 20:45:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-14 20:45:59 -0500 |
commit | f6f223039c0d0683bdea1eabd35b309e10311a60 (patch) | |
tree | 890e07acf8c18ddc2994ebc0a0bdcdda38b0dcc6 /net/mac80211 | |
parent | b3b3f04fb587ecb61b5baa6c1c5f0e666fd12d73 (diff) | |
parent | 42c4568a4ace0adc27a9d6f02936e2047ba6fc7e (diff) |
Merge branch 'master' of ssh://master.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/agg-tx.c | 8 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 25 | ||||
-rw-r--r-- | net/mac80211/debugfs.c | 33 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 42 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 73 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 24 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 19 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 17 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 60 | ||||
-rw-r--r-- | net/mac80211/pm.c | 10 | ||||
-rw-r--r-- | net/mac80211/rate.c | 2 | ||||
-rw-r--r-- | net/mac80211/rate.h | 7 | ||||
-rw-r--r-- | net/mac80211/rx.c | 12 | ||||
-rw-r--r-- | net/mac80211/scan.c | 27 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 731 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 36 | ||||
-rw-r--r-- | net/mac80211/status.c | 17 | ||||
-rw-r--r-- | net/mac80211/tx.c | 11 | ||||
-rw-r--r-- | net/mac80211/util.c | 24 |
19 files changed, 649 insertions, 529 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 718fbcff84d2..5538e1b4a697 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -237,6 +237,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
237 | sdata->vif.type != NL80211_IFTYPE_AP) | 237 | sdata->vif.type != NL80211_IFTYPE_AP) |
238 | return -EINVAL; | 238 | return -EINVAL; |
239 | 239 | ||
240 | if (test_sta_flags(sta, WLAN_STA_DISASSOC)) { | ||
241 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
242 | printk(KERN_DEBUG "Disassociation is in progress. " | ||
243 | "Denying BA session request\n"); | ||
244 | #endif | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
240 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { | 248 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { |
241 | #ifdef CONFIG_MAC80211_HT_DEBUG | 249 | #ifdef CONFIG_MAC80211_HT_DEBUG |
242 | printk(KERN_DEBUG "Suspend in progress. " | 250 | printk(KERN_DEBUG "Suspend in progress. " |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index facf233843e0..e1731b7c2523 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -515,6 +515,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
515 | if (old) | 515 | if (old) |
516 | memcpy(new->tail, old->tail, new_tail_len); | 516 | memcpy(new->tail, old->tail, new_tail_len); |
517 | 517 | ||
518 | sdata->vif.bss_conf.dtim_period = new->dtim_period; | ||
519 | |||
518 | rcu_assign_pointer(sdata->u.ap.beacon, new); | 520 | rcu_assign_pointer(sdata->u.ap.beacon, new); |
519 | 521 | ||
520 | synchronize_rcu(); | 522 | synchronize_rcu(); |
@@ -747,9 +749,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
747 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 749 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
748 | sdata->vif.type == NL80211_IFTYPE_AP; | 750 | sdata->vif.type == NL80211_IFTYPE_AP; |
749 | 751 | ||
750 | rcu_read_lock(); | 752 | err = sta_info_insert_rcu(sta); |
751 | |||
752 | err = sta_info_insert(sta); | ||
753 | if (err) { | 753 | if (err) { |
754 | rcu_read_unlock(); | 754 | rcu_read_unlock(); |
755 | return err; | 755 | return err; |
@@ -768,26 +768,13 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
768 | { | 768 | { |
769 | struct ieee80211_local *local = wiphy_priv(wiphy); | 769 | struct ieee80211_local *local = wiphy_priv(wiphy); |
770 | struct ieee80211_sub_if_data *sdata; | 770 | struct ieee80211_sub_if_data *sdata; |
771 | struct sta_info *sta; | ||
772 | 771 | ||
773 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 772 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
774 | 773 | ||
775 | if (mac) { | 774 | if (mac) |
776 | rcu_read_lock(); | 775 | return sta_info_destroy_addr_bss(sdata, mac); |
777 | |||
778 | sta = sta_info_get_bss(sdata, mac); | ||
779 | if (!sta) { | ||
780 | rcu_read_unlock(); | ||
781 | return -ENOENT; | ||
782 | } | ||
783 | |||
784 | sta_info_unlink(&sta); | ||
785 | rcu_read_unlock(); | ||
786 | |||
787 | sta_info_destroy(sta); | ||
788 | } else | ||
789 | sta_info_flush(local, sdata); | ||
790 | 776 | ||
777 | sta_info_flush(local, sdata); | ||
791 | return 0; | 778 | return 0; |
792 | } | 779 | } |
793 | 780 | ||
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index b3bc32b62a5a..637929b65ccc 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -250,6 +250,38 @@ static const struct file_operations uapsd_max_sp_len_ops = { | |||
250 | .open = mac80211_open_file_generic | 250 | .open = mac80211_open_file_generic |
251 | }; | 251 | }; |
252 | 252 | ||
253 | static ssize_t channel_type_read(struct file *file, char __user *user_buf, | ||
254 | size_t count, loff_t *ppos) | ||
255 | { | ||
256 | struct ieee80211_local *local = file->private_data; | ||
257 | const char *buf; | ||
258 | |||
259 | switch (local->hw.conf.channel_type) { | ||
260 | case NL80211_CHAN_NO_HT: | ||
261 | buf = "no ht\n"; | ||
262 | break; | ||
263 | case NL80211_CHAN_HT20: | ||
264 | buf = "ht20\n"; | ||
265 | break; | ||
266 | case NL80211_CHAN_HT40MINUS: | ||
267 | buf = "ht40-\n"; | ||
268 | break; | ||
269 | case NL80211_CHAN_HT40PLUS: | ||
270 | buf = "ht40+\n"; | ||
271 | break; | ||
272 | default: | ||
273 | buf = "???"; | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | ||
278 | } | ||
279 | |||
280 | static const struct file_operations channel_type_ops = { | ||
281 | .read = channel_type_read, | ||
282 | .open = mac80211_open_file_generic | ||
283 | }; | ||
284 | |||
253 | static ssize_t queues_read(struct file *file, char __user *user_buf, | 285 | static ssize_t queues_read(struct file *file, char __user *user_buf, |
254 | size_t count, loff_t *ppos) | 286 | size_t count, loff_t *ppos) |
255 | { | 287 | { |
@@ -408,6 +440,7 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
408 | DEBUGFS_ADD(noack); | 440 | DEBUGFS_ADD(noack); |
409 | DEBUGFS_ADD(uapsd_queues); | 441 | DEBUGFS_ADD(uapsd_queues); |
410 | DEBUGFS_ADD(uapsd_max_sp_len); | 442 | DEBUGFS_ADD(uapsd_max_sp_len); |
443 | DEBUGFS_ADD(channel_type); | ||
411 | 444 | ||
412 | statsd = debugfs_create_dir("statistics", phyd); | 445 | statsd = debugfs_create_dir("statistics", phyd); |
413 | 446 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 6c31f38ac7f5..c3d844093a2f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -243,6 +243,40 @@ static inline void drv_sta_notify(struct ieee80211_local *local, | |||
243 | trace_drv_sta_notify(local, sdata, cmd, sta); | 243 | trace_drv_sta_notify(local, sdata, cmd, sta); |
244 | } | 244 | } |
245 | 245 | ||
246 | static inline int drv_sta_add(struct ieee80211_local *local, | ||
247 | struct ieee80211_sub_if_data *sdata, | ||
248 | struct ieee80211_sta *sta) | ||
249 | { | ||
250 | int ret = 0; | ||
251 | |||
252 | might_sleep(); | ||
253 | |||
254 | if (local->ops->sta_add) | ||
255 | ret = local->ops->sta_add(&local->hw, &sdata->vif, sta); | ||
256 | else if (local->ops->sta_notify) | ||
257 | local->ops->sta_notify(&local->hw, &sdata->vif, | ||
258 | STA_NOTIFY_ADD, sta); | ||
259 | |||
260 | trace_drv_sta_add(local, sdata, sta, ret); | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | static inline void drv_sta_remove(struct ieee80211_local *local, | ||
266 | struct ieee80211_sub_if_data *sdata, | ||
267 | struct ieee80211_sta *sta) | ||
268 | { | ||
269 | might_sleep(); | ||
270 | |||
271 | if (local->ops->sta_remove) | ||
272 | local->ops->sta_remove(&local->hw, &sdata->vif, sta); | ||
273 | else if (local->ops->sta_notify) | ||
274 | local->ops->sta_notify(&local->hw, &sdata->vif, | ||
275 | STA_NOTIFY_REMOVE, sta); | ||
276 | |||
277 | trace_drv_sta_remove(local, sdata, sta); | ||
278 | } | ||
279 | |||
246 | static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, | 280 | static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, |
247 | const struct ieee80211_tx_queue_params *params) | 281 | const struct ieee80211_tx_queue_params *params) |
248 | { | 282 | { |
@@ -256,14 +290,6 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, | |||
256 | return ret; | 290 | return ret; |
257 | } | 291 | } |
258 | 292 | ||
259 | static inline int drv_get_tx_stats(struct ieee80211_local *local, | ||
260 | struct ieee80211_tx_queue_stats *stats) | ||
261 | { | ||
262 | int ret = local->ops->get_tx_stats(&local->hw, stats); | ||
263 | trace_drv_get_tx_stats(local, stats, ret); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static inline u64 drv_get_tsf(struct ieee80211_local *local) | 293 | static inline u64 drv_get_tsf(struct ieee80211_local *local) |
268 | { | 294 | { |
269 | u64 ret = -1ULL; | 295 | u64 ret = -1ULL; |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 502424b2538a..41baf730a5c7 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -545,59 +545,88 @@ TRACE_EVENT(drv_sta_notify, | |||
545 | ) | 545 | ) |
546 | ); | 546 | ); |
547 | 547 | ||
548 | TRACE_EVENT(drv_conf_tx, | 548 | TRACE_EVENT(drv_sta_add, |
549 | TP_PROTO(struct ieee80211_local *local, u16 queue, | 549 | TP_PROTO(struct ieee80211_local *local, |
550 | const struct ieee80211_tx_queue_params *params, | 550 | struct ieee80211_sub_if_data *sdata, |
551 | int ret), | 551 | struct ieee80211_sta *sta, int ret), |
552 | 552 | ||
553 | TP_ARGS(local, queue, params, ret), | 553 | TP_ARGS(local, sdata, sta, ret), |
554 | 554 | ||
555 | TP_STRUCT__entry( | 555 | TP_STRUCT__entry( |
556 | LOCAL_ENTRY | 556 | LOCAL_ENTRY |
557 | __field(u16, queue) | 557 | VIF_ENTRY |
558 | __field(u16, txop) | 558 | STA_ENTRY |
559 | __field(u16, cw_min) | ||
560 | __field(u16, cw_max) | ||
561 | __field(u8, aifs) | ||
562 | __field(int, ret) | 559 | __field(int, ret) |
563 | ), | 560 | ), |
564 | 561 | ||
565 | TP_fast_assign( | 562 | TP_fast_assign( |
566 | LOCAL_ASSIGN; | 563 | LOCAL_ASSIGN; |
567 | __entry->queue = queue; | 564 | VIF_ASSIGN; |
565 | STA_ASSIGN; | ||
568 | __entry->ret = ret; | 566 | __entry->ret = ret; |
569 | __entry->txop = params->txop; | ||
570 | __entry->cw_max = params->cw_max; | ||
571 | __entry->cw_min = params->cw_min; | ||
572 | __entry->aifs = params->aifs; | ||
573 | ), | 567 | ), |
574 | 568 | ||
575 | TP_printk( | 569 | TP_printk( |
576 | LOCAL_PR_FMT " queue:%d ret:%d", | 570 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d", |
577 | LOCAL_PR_ARG, __entry->queue, __entry->ret | 571 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret |
578 | ) | 572 | ) |
579 | ); | 573 | ); |
580 | 574 | ||
581 | TRACE_EVENT(drv_get_tx_stats, | 575 | TRACE_EVENT(drv_sta_remove, |
582 | TP_PROTO(struct ieee80211_local *local, | 576 | TP_PROTO(struct ieee80211_local *local, |
583 | struct ieee80211_tx_queue_stats *stats, | 577 | struct ieee80211_sub_if_data *sdata, |
578 | struct ieee80211_sta *sta), | ||
579 | |||
580 | TP_ARGS(local, sdata, sta), | ||
581 | |||
582 | TP_STRUCT__entry( | ||
583 | LOCAL_ENTRY | ||
584 | VIF_ENTRY | ||
585 | STA_ENTRY | ||
586 | ), | ||
587 | |||
588 | TP_fast_assign( | ||
589 | LOCAL_ASSIGN; | ||
590 | VIF_ASSIGN; | ||
591 | STA_ASSIGN; | ||
592 | ), | ||
593 | |||
594 | TP_printk( | ||
595 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT, | ||
596 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | ||
597 | ) | ||
598 | ); | ||
599 | |||
600 | TRACE_EVENT(drv_conf_tx, | ||
601 | TP_PROTO(struct ieee80211_local *local, u16 queue, | ||
602 | const struct ieee80211_tx_queue_params *params, | ||
584 | int ret), | 603 | int ret), |
585 | 604 | ||
586 | TP_ARGS(local, stats, ret), | 605 | TP_ARGS(local, queue, params, ret), |
587 | 606 | ||
588 | TP_STRUCT__entry( | 607 | TP_STRUCT__entry( |
589 | LOCAL_ENTRY | 608 | LOCAL_ENTRY |
609 | __field(u16, queue) | ||
610 | __field(u16, txop) | ||
611 | __field(u16, cw_min) | ||
612 | __field(u16, cw_max) | ||
613 | __field(u8, aifs) | ||
590 | __field(int, ret) | 614 | __field(int, ret) |
591 | ), | 615 | ), |
592 | 616 | ||
593 | TP_fast_assign( | 617 | TP_fast_assign( |
594 | LOCAL_ASSIGN; | 618 | LOCAL_ASSIGN; |
619 | __entry->queue = queue; | ||
595 | __entry->ret = ret; | 620 | __entry->ret = ret; |
621 | __entry->txop = params->txop; | ||
622 | __entry->cw_max = params->cw_max; | ||
623 | __entry->cw_min = params->cw_min; | ||
624 | __entry->aifs = params->aifs; | ||
596 | ), | 625 | ), |
597 | 626 | ||
598 | TP_printk( | 627 | TP_printk( |
599 | LOCAL_PR_FMT " ret:%d", | 628 | LOCAL_PR_FMT " queue:%d ret:%d", |
600 | LOCAL_PR_ARG, __entry->ret | 629 | LOCAL_PR_ARG, __entry->queue, __entry->ret |
601 | ) | 630 | ) |
602 | ); | 631 | ); |
603 | 632 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f95750b423e3..f3e942486749 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -275,10 +275,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
275 | (unsigned long long) supp_rates, | 275 | (unsigned long long) supp_rates, |
276 | (unsigned long long) sta->sta.supp_rates[band]); | 276 | (unsigned long long) sta->sta.supp_rates[band]); |
277 | #endif | 277 | #endif |
278 | } else | 278 | rcu_read_unlock(); |
279 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 279 | } else { |
280 | 280 | rcu_read_unlock(); | |
281 | rcu_read_unlock(); | 281 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
282 | supp_rates, GFP_KERNEL); | ||
283 | } | ||
282 | } | 284 | } |
283 | 285 | ||
284 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 286 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
@@ -368,7 +370,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
368 | sdata->name, mgmt->bssid); | 370 | sdata->name, mgmt->bssid); |
369 | #endif | 371 | #endif |
370 | ieee80211_sta_join_ibss(sdata, bss); | 372 | ieee80211_sta_join_ibss(sdata, bss); |
371 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 373 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
374 | supp_rates, GFP_KERNEL); | ||
372 | } | 375 | } |
373 | 376 | ||
374 | put_bss: | 377 | put_bss: |
@@ -381,7 +384,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
381 | * must be callable in atomic context. | 384 | * must be callable in atomic context. |
382 | */ | 385 | */ |
383 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 386 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
384 | u8 *bssid,u8 *addr, u32 supp_rates) | 387 | u8 *bssid,u8 *addr, u32 supp_rates, |
388 | gfp_t gfp) | ||
385 | { | 389 | { |
386 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 390 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
387 | struct ieee80211_local *local = sdata->local; | 391 | struct ieee80211_local *local = sdata->local; |
@@ -410,7 +414,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
410 | wiphy_name(local->hw.wiphy), addr, sdata->name); | 414 | wiphy_name(local->hw.wiphy), addr, sdata->name); |
411 | #endif | 415 | #endif |
412 | 416 | ||
413 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 417 | sta = sta_info_alloc(sdata, addr, gfp); |
414 | if (!sta) | 418 | if (!sta) |
415 | return NULL; | 419 | return NULL; |
416 | 420 | ||
@@ -422,9 +426,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
422 | 426 | ||
423 | rate_control_rate_init(sta); | 427 | rate_control_rate_init(sta); |
424 | 428 | ||
429 | /* If it fails, maybe we raced another insertion? */ | ||
425 | if (sta_info_insert(sta)) | 430 | if (sta_info_insert(sta)) |
426 | return NULL; | 431 | return sta_info_get(sdata, addr); |
427 | |||
428 | return sta; | 432 | return sta; |
429 | } | 433 | } |
430 | 434 | ||
@@ -652,7 +656,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
652 | } | 656 | } |
653 | if (pos[1] != 0 && | 657 | if (pos[1] != 0 && |
654 | (pos[1] != ifibss->ssid_len || | 658 | (pos[1] != ifibss->ssid_len || |
655 | !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { | 659 | memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { |
656 | /* Ignore ProbeReq for foreign SSID */ | 660 | /* Ignore ProbeReq for foreign SSID */ |
657 | return; | 661 | return; |
658 | } | 662 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3067fbd69d63..9dd98b674cbc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -316,6 +316,7 @@ enum ieee80211_sta_flags { | |||
316 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | 316 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
317 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 317 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
318 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | 318 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
319 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), | ||
319 | }; | 320 | }; |
320 | 321 | ||
321 | struct ieee80211_if_managed { | 322 | struct ieee80211_if_managed { |
@@ -688,15 +689,18 @@ struct ieee80211_local { | |||
688 | 689 | ||
689 | /* Station data */ | 690 | /* Station data */ |
690 | /* | 691 | /* |
691 | * The lock only protects the list, hash, timer and counter | 692 | * The mutex only protects the list and counter, |
692 | * against manipulation, reads are done in RCU. Additionally, | 693 | * reads are done in RCU. |
693 | * the lock protects each BSS's TIM bitmap. | 694 | * Additionally, the lock protects the hash table, |
695 | * the pending list and each BSS's TIM bitmap. | ||
694 | */ | 696 | */ |
697 | struct mutex sta_mtx; | ||
695 | spinlock_t sta_lock; | 698 | spinlock_t sta_lock; |
696 | unsigned long num_sta; | 699 | unsigned long num_sta; |
697 | struct list_head sta_list; | 700 | struct list_head sta_list, sta_pending_list; |
698 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 701 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
699 | struct timer_list sta_cleanup; | 702 | struct timer_list sta_cleanup; |
703 | struct work_struct sta_finish_work; | ||
700 | int sta_generation; | 704 | int sta_generation; |
701 | 705 | ||
702 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 706 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
@@ -770,10 +774,6 @@ struct ieee80211_local { | |||
770 | assoc_led_name[32], radio_led_name[32]; | 774 | assoc_led_name[32], radio_led_name[32]; |
771 | #endif | 775 | #endif |
772 | 776 | ||
773 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
774 | struct work_struct sta_debugfs_add; | ||
775 | #endif | ||
776 | |||
777 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 777 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
778 | /* TX/RX handler statistics */ | 778 | /* TX/RX handler statistics */ |
779 | unsigned int tx_handlers_drop; | 779 | unsigned int tx_handlers_drop; |
@@ -985,7 +985,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); | |||
985 | ieee80211_rx_result | 985 | ieee80211_rx_result |
986 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 986 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
987 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 987 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
988 | u8 *bssid, u8 *addr, u32 supp_rates); | 988 | u8 *bssid, u8 *addr, u32 supp_rates, |
989 | gfp_t gfp); | ||
989 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 990 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
990 | struct cfg80211_ibss_params *params); | 991 | struct cfg80211_ibss_params *params); |
991 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | 992 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 7985e5150898..bc4e20e57ff5 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -102,7 +102,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
102 | if (local->num_sta >= MESH_MAX_PLINKS) | 102 | if (local->num_sta >= MESH_MAX_PLINKS) |
103 | return NULL; | 103 | return NULL; |
104 | 104 | ||
105 | sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); | 105 | sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); |
106 | if (!sta) | 106 | if (!sta) |
107 | return NULL; | 107 | return NULL; |
108 | 108 | ||
@@ -236,12 +236,12 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data | |||
236 | 236 | ||
237 | sta = sta_info_get(sdata, hw_addr); | 237 | sta = sta_info_get(sdata, hw_addr); |
238 | if (!sta) { | 238 | if (!sta) { |
239 | rcu_read_unlock(); | ||
240 | |||
239 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | 241 | sta = mesh_plink_alloc(sdata, hw_addr, rates); |
240 | if (!sta) { | 242 | if (!sta) |
241 | rcu_read_unlock(); | ||
242 | return; | 243 | return; |
243 | } | 244 | if (sta_info_insert_rcu(sta)) { |
244 | if (sta_info_insert(sta)) { | ||
245 | rcu_read_unlock(); | 245 | rcu_read_unlock(); |
246 | return; | 246 | return; |
247 | } | 247 | } |
@@ -485,9 +485,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
485 | } else if (!sta) { | 485 | } else if (!sta) { |
486 | /* ftype == PLINK_OPEN */ | 486 | /* ftype == PLINK_OPEN */ |
487 | u32 rates; | 487 | u32 rates; |
488 | |||
489 | rcu_read_unlock(); | ||
490 | |||
488 | if (!mesh_plink_free_count(sdata)) { | 491 | if (!mesh_plink_free_count(sdata)) { |
489 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 492 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
490 | rcu_read_unlock(); | ||
491 | return; | 493 | return; |
492 | } | 494 | } |
493 | 495 | ||
@@ -495,10 +497,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
495 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); | 497 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); |
496 | if (!sta) { | 498 | if (!sta) { |
497 | mpl_dbg("Mesh plink error: plink table full\n"); | 499 | mpl_dbg("Mesh plink error: plink table full\n"); |
498 | rcu_read_unlock(); | ||
499 | return; | 500 | return; |
500 | } | 501 | } |
501 | if (sta_info_insert(sta)) { | 502 | if (sta_info_insert_rcu(sta)) { |
502 | rcu_read_unlock(); | 503 | rcu_read_unlock(); |
503 | return; | 504 | return; |
504 | } | 505 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86c6ad1b058d..bfc4a5070013 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -27,10 +27,6 @@ | |||
27 | #include "rate.h" | 27 | #include "rate.h" |
28 | #include "led.h" | 28 | #include "led.h" |
29 | 29 | ||
30 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | ||
31 | #define IEEE80211_AUTH_MAX_TRIES 3 | ||
32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | ||
33 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
34 | #define IEEE80211_MAX_PROBE_TRIES 5 | 30 | #define IEEE80211_MAX_PROBE_TRIES 5 |
35 | 31 | ||
36 | /* | 32 | /* |
@@ -438,8 +434,11 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, | |||
438 | } else { | 434 | } else { |
439 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 435 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
440 | ieee80211_send_nullfunc(local, sdata, 1); | 436 | ieee80211_send_nullfunc(local, sdata, 1); |
441 | conf->flags |= IEEE80211_CONF_PS; | 437 | |
442 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 438 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
439 | conf->flags |= IEEE80211_CONF_PS; | ||
440 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
441 | } | ||
443 | } | 442 | } |
444 | } | 443 | } |
445 | 444 | ||
@@ -545,6 +544,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
545 | container_of(work, struct ieee80211_local, | 544 | container_of(work, struct ieee80211_local, |
546 | dynamic_ps_enable_work); | 545 | dynamic_ps_enable_work); |
547 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | 546 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; |
547 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
548 | 548 | ||
549 | /* can only happen when PS was just disabled anyway */ | 549 | /* can only happen when PS was just disabled anyway */ |
550 | if (!sdata) | 550 | if (!sdata) |
@@ -553,11 +553,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
553 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 553 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
554 | return; | 554 | return; |
555 | 555 | ||
556 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 556 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
557 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) | ||
557 | ieee80211_send_nullfunc(local, sdata, 1); | 558 | ieee80211_send_nullfunc(local, sdata, 1); |
558 | 559 | ||
559 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 560 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) || |
560 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 561 | (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { |
562 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | ||
563 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
564 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
565 | } | ||
561 | } | 566 | } |
562 | 567 | ||
563 | void ieee80211_dynamic_ps_timer(unsigned long data) | 568 | void ieee80211_dynamic_ps_timer(unsigned long data) |
@@ -792,8 +797,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
792 | 797 | ||
793 | rcu_read_lock(); | 798 | rcu_read_lock(); |
794 | sta = sta_info_get(sdata, bssid); | 799 | sta = sta_info_get(sdata, bssid); |
795 | if (sta) | 800 | if (sta) { |
801 | set_sta_flags(sta, WLAN_STA_DISASSOC); | ||
796 | ieee80211_sta_tear_down_BA_sessions(sta); | 802 | ieee80211_sta_tear_down_BA_sessions(sta); |
803 | } | ||
797 | rcu_read_unlock(); | 804 | rcu_read_unlock(); |
798 | 805 | ||
799 | changed |= ieee80211_reset_erp_info(sdata); | 806 | changed |= ieee80211_reset_erp_info(sdata); |
@@ -826,19 +833,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
826 | changed |= BSS_CHANGED_BSSID; | 833 | changed |= BSS_CHANGED_BSSID; |
827 | ieee80211_bss_info_change_notify(sdata, changed); | 834 | ieee80211_bss_info_change_notify(sdata, changed); |
828 | 835 | ||
829 | rcu_read_lock(); | 836 | sta_info_destroy_addr(sdata, bssid); |
830 | |||
831 | sta = sta_info_get(sdata, bssid); | ||
832 | if (!sta) { | ||
833 | rcu_read_unlock(); | ||
834 | return; | ||
835 | } | ||
836 | |||
837 | sta_info_unlink(&sta); | ||
838 | |||
839 | rcu_read_unlock(); | ||
840 | |||
841 | sta_info_destroy(sta); | ||
842 | } | 837 | } |
843 | 838 | ||
844 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 839 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -1844,7 +1839,11 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
1844 | wk->probe_auth.algorithm = auth_alg; | 1839 | wk->probe_auth.algorithm = auth_alg; |
1845 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; | 1840 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; |
1846 | 1841 | ||
1847 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | 1842 | /* if we already have a probe, don't probe again */ |
1843 | if (req->bss->proberesp_ies) | ||
1844 | wk->type = IEEE80211_WORK_AUTH; | ||
1845 | else | ||
1846 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | ||
1848 | wk->chan = req->bss->channel; | 1847 | wk->chan = req->bss->channel; |
1849 | wk->sdata = sdata; | 1848 | wk->sdata = sdata; |
1850 | wk->done = ieee80211_probe_auth_done; | 1849 | wk->done = ieee80211_probe_auth_done; |
@@ -1904,6 +1903,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
1904 | return -ENOMEM; | 1903 | return -ENOMEM; |
1905 | 1904 | ||
1906 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 1905 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
1906 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | ||
1907 | 1907 | ||
1908 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) | 1908 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) |
1909 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | 1909 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || |
@@ -2007,12 +2007,18 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2007 | 2007 | ||
2008 | mutex_lock(&local->work_mtx); | 2008 | mutex_lock(&local->work_mtx); |
2009 | list_for_each_entry(wk, &local->work_list, list) { | 2009 | list_for_each_entry(wk, &local->work_list, list) { |
2010 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE) | 2010 | if (wk->sdata != sdata) |
2011 | continue; | ||
2012 | |||
2013 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE && | ||
2014 | wk->type != IEEE80211_WORK_AUTH) | ||
2011 | continue; | 2015 | continue; |
2016 | |||
2012 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) | 2017 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) |
2013 | continue; | 2018 | continue; |
2014 | not_auth_yet = true; | 2019 | |
2015 | list_del(&wk->list); | 2020 | not_auth_yet = wk->type == IEEE80211_WORK_DIRECT_PROBE; |
2021 | list_del_rcu(&wk->list); | ||
2016 | free_work(wk); | 2022 | free_work(wk); |
2017 | break; | 2023 | break; |
2018 | } | 2024 | } |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 47f818959ad7..0e64484e861c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -11,7 +11,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
11 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
13 | struct sta_info *sta; | 13 | struct sta_info *sta; |
14 | unsigned long flags; | ||
15 | 14 | ||
16 | ieee80211_scan_cancel(local); | 15 | ieee80211_scan_cancel(local); |
17 | 16 | ||
@@ -55,22 +54,21 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
55 | rcu_read_unlock(); | 54 | rcu_read_unlock(); |
56 | 55 | ||
57 | /* remove STAs */ | 56 | /* remove STAs */ |
58 | spin_lock_irqsave(&local->sta_lock, flags); | 57 | mutex_lock(&local->sta_mtx); |
59 | list_for_each_entry(sta, &local->sta_list, list) { | 58 | list_for_each_entry(sta, &local->sta_list, list) { |
60 | if (local->ops->sta_notify) { | 59 | if (sta->uploaded) { |
61 | sdata = sta->sdata; | 60 | sdata = sta->sdata; |
62 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 61 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
63 | sdata = container_of(sdata->bss, | 62 | sdata = container_of(sdata->bss, |
64 | struct ieee80211_sub_if_data, | 63 | struct ieee80211_sub_if_data, |
65 | u.ap); | 64 | u.ap); |
66 | 65 | ||
67 | drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE, | 66 | drv_sta_remove(local, sdata, &sta->sta); |
68 | &sta->sta); | ||
69 | } | 67 | } |
70 | 68 | ||
71 | mesh_plink_quiesce(sta); | 69 | mesh_plink_quiesce(sta); |
72 | } | 70 | } |
73 | spin_unlock_irqrestore(&local->sta_lock, flags); | 71 | mutex_unlock(&local->sta_mtx); |
74 | 72 | ||
75 | /* remove all interfaces */ | 73 | /* remove all interfaces */ |
76 | list_for_each_entry(sdata, &local->interfaces, list) { | 74 | list_for_each_entry(sdata, &local->interfaces, list) { |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index c74b7c85403c..99ab24cc9783 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -145,7 +145,7 @@ static const struct file_operations rcname_ops = { | |||
145 | }; | 145 | }; |
146 | #endif | 146 | #endif |
147 | 147 | ||
148 | struct rate_control_ref *rate_control_alloc(const char *name, | 148 | static struct rate_control_ref *rate_control_alloc(const char *name, |
149 | struct ieee80211_local *local) | 149 | struct ieee80211_local *local) |
150 | { | 150 | { |
151 | struct dentry *debugfsdir = NULL; | 151 | struct dentry *debugfsdir = NULL; |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 998cf7a935b6..b6108bca96d4 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -26,10 +26,6 @@ struct rate_control_ref { | |||
26 | struct kref kref; | 26 | struct kref kref; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the | ||
30 | * first available algorithm. */ | ||
31 | struct rate_control_ref *rate_control_alloc(const char *name, | ||
32 | struct ieee80211_local *local); | ||
33 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | 29 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
34 | struct sta_info *sta, | 30 | struct sta_info *sta, |
35 | struct ieee80211_tx_rate_control *txrc); | 31 | struct ieee80211_tx_rate_control *txrc); |
@@ -116,7 +112,8 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) | |||
116 | #endif | 112 | #endif |
117 | } | 113 | } |
118 | 114 | ||
119 | /* functions for rate control related to a device */ | 115 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the |
116 | * first available algorithm. */ | ||
120 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | 117 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, |
121 | const char *name); | 118 | const char *name); |
122 | void rate_control_deinitialize(struct ieee80211_local *local); | 119 | void rate_control_deinitialize(struct ieee80211_local *local); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5709307fcb9b..c9755f3d986c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1719,6 +1719,7 @@ static ieee80211_rx_result debug_noinline | |||
1719 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | 1719 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) |
1720 | { | 1720 | { |
1721 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1721 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
1722 | struct ieee80211_local *local = rx->local; | ||
1722 | struct net_device *dev = sdata->dev; | 1723 | struct net_device *dev = sdata->dev; |
1723 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1724 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1724 | __le16 fc = hdr->frame_control; | 1725 | __le16 fc = hdr->frame_control; |
@@ -1750,6 +1751,13 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1750 | dev->stats.rx_packets++; | 1751 | dev->stats.rx_packets++; |
1751 | dev->stats.rx_bytes += rx->skb->len; | 1752 | dev->stats.rx_bytes += rx->skb->len; |
1752 | 1753 | ||
1754 | if (ieee80211_is_data(hdr->frame_control) && | ||
1755 | !is_multicast_ether_addr(hdr->addr1) && | ||
1756 | local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) { | ||
1757 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
1758 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
1759 | } | ||
1760 | |||
1753 | ieee80211_deliver_skb(rx); | 1761 | ieee80211_deliver_skb(rx); |
1754 | 1762 | ||
1755 | return RX_QUEUED; | 1763 | return RX_QUEUED; |
@@ -2244,8 +2252,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2244 | rate_idx = 0; /* TODO: HT rates */ | 2252 | rate_idx = 0; /* TODO: HT rates */ |
2245 | else | 2253 | else |
2246 | rate_idx = status->rate_idx; | 2254 | rate_idx = status->rate_idx; |
2247 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, | 2255 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, |
2248 | BIT(rate_idx)); | 2256 | hdr->addr2, BIT(rate_idx), GFP_ATOMIC); |
2249 | } | 2257 | } |
2250 | break; | 2258 | break; |
2251 | case NL80211_IFTYPE_MESH_POINT: | 2259 | case NL80211_IFTYPE_MESH_POINT: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index bc061f629674..b822dce97867 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -345,6 +345,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
345 | if (local->scan_req) | 345 | if (local->scan_req) |
346 | return -EBUSY; | 346 | return -EBUSY; |
347 | 347 | ||
348 | if (!list_empty(&local->work_list)) { | ||
349 | /* wait for the work to finish/time out */ | ||
350 | local->scan_req = req; | ||
351 | local->scan_sdata = sdata; | ||
352 | return 0; | ||
353 | } | ||
354 | |||
348 | if (local->ops->hw_scan) { | 355 | if (local->ops->hw_scan) { |
349 | u8 *ies; | 356 | u8 *ies; |
350 | 357 | ||
@@ -364,29 +371,33 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
364 | local->hw_scan_req->ie = ies; | 371 | local->hw_scan_req->ie = ies; |
365 | 372 | ||
366 | local->hw_scan_band = 0; | 373 | local->hw_scan_band = 0; |
374 | |||
375 | /* | ||
376 | * After allocating local->hw_scan_req, we must | ||
377 | * go through until ieee80211_prep_hw_scan(), so | ||
378 | * anything that might be changed here and leave | ||
379 | * this function early must not go after this | ||
380 | * allocation. | ||
381 | */ | ||
367 | } | 382 | } |
368 | 383 | ||
369 | local->scan_req = req; | 384 | local->scan_req = req; |
370 | local->scan_sdata = sdata; | 385 | local->scan_sdata = sdata; |
371 | 386 | ||
372 | if (!list_empty(&local->work_list)) { | ||
373 | /* wait for the work to finish/time out */ | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | if (local->ops->hw_scan) | 387 | if (local->ops->hw_scan) |
378 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 388 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
379 | else | 389 | else |
380 | __set_bit(SCAN_SW_SCANNING, &local->scanning); | 390 | __set_bit(SCAN_SW_SCANNING, &local->scanning); |
391 | |||
381 | /* | 392 | /* |
382 | * Kicking off the scan need not be protected, | 393 | * Kicking off the scan need not be protected, |
383 | * only the scan variable stuff, since now | 394 | * only the scan variable stuff, since now |
384 | * local->scan_req is assigned and other callers | 395 | * local->scan_req is assigned and other callers |
385 | * will abort their scan attempts. | 396 | * will abort their scan attempts. |
386 | * | 397 | * |
387 | * This avoids getting a scan_mtx -> iflist_mtx | 398 | * This avoids too many locking dependencies |
388 | * dependency, so that the scan completed calls | 399 | * so that the scan completed calls have more |
389 | * have more locking freedom. | 400 | * locking freedom. |
390 | */ | 401 | */ |
391 | 402 | ||
392 | ieee80211_recalc_idle(local); | 403 | ieee80211_recalc_idle(local); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f735826f055c..211c475f73c6 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -32,49 +32,33 @@ | |||
32 | * for faster lookup and a list for iteration. They are managed using | 32 | * for faster lookup and a list for iteration. They are managed using |
33 | * RCU, i.e. access to the list and hash table is protected by RCU. | 33 | * RCU, i.e. access to the list and hash table is protected by RCU. |
34 | * | 34 | * |
35 | * Upon allocating a STA info structure with sta_info_alloc(), the caller owns | 35 | * Upon allocating a STA info structure with sta_info_alloc(), the caller |
36 | * that structure. It must then either destroy it using sta_info_destroy() | 36 | * owns that structure. It must then insert it into the hash table using |
37 | * (which is pretty useless) or insert it into the hash table using | 37 | * either sta_info_insert() or sta_info_insert_rcu(); only in the latter |
38 | * sta_info_insert() which demotes the reference from ownership to a regular | 38 | * case (which acquires an rcu read section but must not be called from |
39 | * RCU-protected reference; if the function is called without protection by an | 39 | * within one) will the pointer still be valid after the call. Note that |
40 | * RCU critical section the reference is instantly invalidated. Note that the | 40 | * the caller may not do much with the STA info before inserting it, in |
41 | * caller may not do much with the STA info before inserting it, in particular, | 41 | * particular, it may not start any mesh peer link management or add |
42 | * it may not start any mesh peer link management or add encryption keys. | 42 | * encryption keys. |
43 | * | 43 | * |
44 | * When the insertion fails (sta_info_insert()) returns non-zero), the | 44 | * When the insertion fails (sta_info_insert()) returns non-zero), the |
45 | * structure will have been freed by sta_info_insert()! | 45 | * structure will have been freed by sta_info_insert()! |
46 | * | 46 | * |
47 | * sta entries are added by mac80211 when you establish a link with a | 47 | * Station entries are added by mac80211 when you establish a link with a |
48 | * peer. This means different things for the different type of interfaces | 48 | * peer. This means different things for the different type of interfaces |
49 | * we support. For a regular station this mean we add the AP sta when we | 49 | * we support. For a regular station this mean we add the AP sta when we |
50 | * receive an assocation response from the AP. For IBSS this occurs when | 50 | * receive an assocation response from the AP. For IBSS this occurs when |
51 | * we receive a probe response or a beacon from target IBSS network. For | 51 | * get to know about a peer on the same IBSS. For WDS we add the sta for |
52 | * WDS we add the sta for the peer imediately upon device open. When using | 52 | * the peer imediately upon device open. When using AP mode we add stations |
53 | * AP mode we add stations for each respective station upon request from | 53 | * for each respective station upon request from userspace through nl80211. |
54 | * userspace through nl80211. | ||
55 | * | 54 | * |
56 | * Because there are debugfs entries for each station, and adding those | 55 | * In order to remove a STA info structure, various sta_info_destroy_*() |
57 | * must be able to sleep, it is also possible to "pin" a station entry, | 56 | * calls are available. |
58 | * that means it can be removed from the hash table but not be freed. | ||
59 | * See the comment in __sta_info_unlink() for more information, this is | ||
60 | * an internal capability only. | ||
61 | * | 57 | * |
62 | * In order to remove a STA info structure, the caller needs to first | 58 | * There is no concept of ownership on a STA entry, each structure is |
63 | * unlink it (sta_info_unlink()) from the list and hash tables and | 59 | * owned by the global hash table/list until it is removed. All users of |
64 | * then destroy it; sta_info_destroy() will wait for an RCU grace period | 60 | * the structure need to be RCU protected so that the structure won't be |
65 | * to elapse before actually freeing it. Due to the pinning and the | 61 | * freed before they are done using it. |
66 | * possibility of multiple callers trying to remove the same STA info at | ||
67 | * the same time, sta_info_unlink() can clear the STA info pointer it is | ||
68 | * passed to indicate that the STA info is owned by somebody else now. | ||
69 | * | ||
70 | * If sta_info_unlink() did not clear the pointer then the caller owns | ||
71 | * the STA info structure now and is responsible of destroying it with | ||
72 | * a call to sta_info_destroy(). | ||
73 | * | ||
74 | * In all other cases, there is no concept of ownership on a STA entry, | ||
75 | * each structure is owned by the global hash table/list until it is | ||
76 | * removed. All users of the structure need to be RCU protected so that | ||
77 | * the structure won't be freed before they are done using it. | ||
78 | */ | 62 | */ |
79 | 63 | ||
80 | /* Caller must hold local->sta_lock */ | 64 | /* Caller must hold local->sta_lock */ |
@@ -185,101 +169,6 @@ static void __sta_info_free(struct ieee80211_local *local, | |||
185 | kfree(sta); | 169 | kfree(sta); |
186 | } | 170 | } |
187 | 171 | ||
188 | void sta_info_destroy(struct sta_info *sta) | ||
189 | { | ||
190 | struct ieee80211_local *local; | ||
191 | struct sk_buff *skb; | ||
192 | int i; | ||
193 | |||
194 | might_sleep(); | ||
195 | |||
196 | if (!sta) | ||
197 | return; | ||
198 | |||
199 | local = sta->local; | ||
200 | |||
201 | cancel_work_sync(&sta->drv_unblock_wk); | ||
202 | |||
203 | rate_control_remove_sta_debugfs(sta); | ||
204 | ieee80211_sta_debugfs_remove(sta); | ||
205 | |||
206 | #ifdef CONFIG_MAC80211_MESH | ||
207 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
208 | mesh_plink_deactivate(sta); | ||
209 | #endif | ||
210 | |||
211 | /* | ||
212 | * We have only unlinked the key, and actually destroying it | ||
213 | * may mean it is removed from hardware which requires that | ||
214 | * the key->sta pointer is still valid, so flush the key todo | ||
215 | * list here. | ||
216 | * | ||
217 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
218 | * nothing can reference this sta struct any more. | ||
219 | */ | ||
220 | ieee80211_key_todo(); | ||
221 | |||
222 | #ifdef CONFIG_MAC80211_MESH | ||
223 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
224 | del_timer_sync(&sta->plink_timer); | ||
225 | #endif | ||
226 | |||
227 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
228 | local->total_ps_buffered--; | ||
229 | dev_kfree_skb_any(skb); | ||
230 | } | ||
231 | |||
232 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
233 | dev_kfree_skb_any(skb); | ||
234 | |||
235 | for (i = 0; i < STA_TID_NUM; i++) { | ||
236 | struct tid_ampdu_rx *tid_rx; | ||
237 | struct tid_ampdu_tx *tid_tx; | ||
238 | |||
239 | spin_lock_bh(&sta->lock); | ||
240 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
241 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
242 | if (tid_rx) | ||
243 | tid_rx->shutdown = true; | ||
244 | |||
245 | spin_unlock_bh(&sta->lock); | ||
246 | |||
247 | /* | ||
248 | * Outside spinlock - shutdown is true now so that the timer | ||
249 | * won't free tid_rx, we have to do that now. Can't let the | ||
250 | * timer do it because we have to sync the timer outside the | ||
251 | * lock that it takes itself. | ||
252 | */ | ||
253 | if (tid_rx) { | ||
254 | del_timer_sync(&tid_rx->session_timer); | ||
255 | kfree(tid_rx); | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * No need to do such complications for TX agg sessions, the | ||
260 | * path leading to freeing the tid_tx struct goes via a call | ||
261 | * from the driver, and thus needs to look up the sta struct | ||
262 | * again, which cannot be found when we get here. Hence, we | ||
263 | * just need to delete the timer and free the aggregation | ||
264 | * info; we won't be telling the peer about it then but that | ||
265 | * doesn't matter if we're not talking to it again anyway. | ||
266 | */ | ||
267 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
268 | if (tid_tx) { | ||
269 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
270 | /* | ||
271 | * STA removed while aggregation session being | ||
272 | * started? Bit odd, but purge frames anyway. | ||
273 | */ | ||
274 | skb_queue_purge(&tid_tx->pending); | ||
275 | kfree(tid_tx); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | __sta_info_free(local, sta); | ||
280 | } | ||
281 | |||
282 | |||
283 | /* Caller must hold local->sta_lock */ | 172 | /* Caller must hold local->sta_lock */ |
284 | static void sta_info_hash_add(struct ieee80211_local *local, | 173 | static void sta_info_hash_add(struct ieee80211_local *local, |
285 | struct sta_info *sta) | 174 | struct sta_info *sta) |
@@ -376,7 +265,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
376 | return sta; | 265 | return sta; |
377 | } | 266 | } |
378 | 267 | ||
379 | int sta_info_insert(struct sta_info *sta) | 268 | static int sta_info_finish_insert(struct sta_info *sta, bool async) |
380 | { | 269 | { |
381 | struct ieee80211_local *local = sta->local; | 270 | struct ieee80211_local *local = sta->local; |
382 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 271 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -384,6 +273,91 @@ int sta_info_insert(struct sta_info *sta) | |||
384 | unsigned long flags; | 273 | unsigned long flags; |
385 | int err = 0; | 274 | int err = 0; |
386 | 275 | ||
276 | WARN_ON(!mutex_is_locked(&local->sta_mtx)); | ||
277 | |||
278 | /* notify driver */ | ||
279 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
280 | sdata = container_of(sdata->bss, | ||
281 | struct ieee80211_sub_if_data, | ||
282 | u.ap); | ||
283 | err = drv_sta_add(local, sdata, &sta->sta); | ||
284 | if (err) { | ||
285 | if (!async) | ||
286 | return err; | ||
287 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)" | ||
288 | " - keeping it anyway.\n", | ||
289 | sdata->name, sta->sta.addr, err); | ||
290 | } else { | ||
291 | sta->uploaded = true; | ||
292 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
293 | if (async) | ||
294 | printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n", | ||
295 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
296 | #endif | ||
297 | } | ||
298 | |||
299 | sdata = sta->sdata; | ||
300 | |||
301 | if (!async) { | ||
302 | local->num_sta++; | ||
303 | local->sta_generation++; | ||
304 | smp_mb(); | ||
305 | |||
306 | /* make the station visible */ | ||
307 | spin_lock_irqsave(&local->sta_lock, flags); | ||
308 | sta_info_hash_add(local, sta); | ||
309 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
310 | } | ||
311 | |||
312 | list_add(&sta->list, &local->sta_list); | ||
313 | |||
314 | ieee80211_sta_debugfs_add(sta); | ||
315 | rate_control_add_sta_debugfs(sta); | ||
316 | |||
317 | sinfo.filled = 0; | ||
318 | sinfo.generation = local->sta_generation; | ||
319 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
320 | |||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static void sta_info_finish_pending(struct ieee80211_local *local) | ||
326 | { | ||
327 | struct sta_info *sta; | ||
328 | unsigned long flags; | ||
329 | |||
330 | spin_lock_irqsave(&local->sta_lock, flags); | ||
331 | while (!list_empty(&local->sta_pending_list)) { | ||
332 | sta = list_first_entry(&local->sta_pending_list, | ||
333 | struct sta_info, list); | ||
334 | list_del(&sta->list); | ||
335 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
336 | |||
337 | sta_info_finish_insert(sta, true); | ||
338 | |||
339 | spin_lock_irqsave(&local->sta_lock, flags); | ||
340 | } | ||
341 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
342 | } | ||
343 | |||
344 | static void sta_info_finish_work(struct work_struct *work) | ||
345 | { | ||
346 | struct ieee80211_local *local = | ||
347 | container_of(work, struct ieee80211_local, sta_finish_work); | ||
348 | |||
349 | mutex_lock(&local->sta_mtx); | ||
350 | sta_info_finish_pending(local); | ||
351 | mutex_unlock(&local->sta_mtx); | ||
352 | } | ||
353 | |||
354 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | ||
355 | { | ||
356 | struct ieee80211_local *local = sta->local; | ||
357 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
358 | unsigned long flags; | ||
359 | int err = 0; | ||
360 | |||
387 | /* | 361 | /* |
388 | * Can't be a WARN_ON because it can be triggered through a race: | 362 | * Can't be a WARN_ON because it can be triggered through a race: |
389 | * something inserts a STA (on one CPU) without holding the RTNL | 363 | * something inserts a STA (on one CPU) without holding the RTNL |
@@ -391,36 +365,87 @@ int sta_info_insert(struct sta_info *sta) | |||
391 | */ | 365 | */ |
392 | if (unlikely(!ieee80211_sdata_running(sdata))) { | 366 | if (unlikely(!ieee80211_sdata_running(sdata))) { |
393 | err = -ENETDOWN; | 367 | err = -ENETDOWN; |
368 | rcu_read_lock(); | ||
394 | goto out_free; | 369 | goto out_free; |
395 | } | 370 | } |
396 | 371 | ||
397 | if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || | 372 | if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || |
398 | is_multicast_ether_addr(sta->sta.addr))) { | 373 | is_multicast_ether_addr(sta->sta.addr))) { |
399 | err = -EINVAL; | 374 | err = -EINVAL; |
375 | rcu_read_lock(); | ||
400 | goto out_free; | 376 | goto out_free; |
401 | } | 377 | } |
402 | 378 | ||
379 | /* | ||
380 | * In ad-hoc mode, we sometimes need to insert stations | ||
381 | * from tasklet context from the RX path. To avoid races, | ||
382 | * always do so in that case -- see the comment below. | ||
383 | */ | ||
384 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
385 | spin_lock_irqsave(&local->sta_lock, flags); | ||
386 | /* check if STA exists already */ | ||
387 | if (sta_info_get_bss(sdata, sta->sta.addr)) { | ||
388 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
389 | rcu_read_lock(); | ||
390 | err = -EEXIST; | ||
391 | goto out_free; | ||
392 | } | ||
393 | |||
394 | local->num_sta++; | ||
395 | local->sta_generation++; | ||
396 | smp_mb(); | ||
397 | sta_info_hash_add(local, sta); | ||
398 | |||
399 | list_add_tail(&sta->list, &local->sta_pending_list); | ||
400 | |||
401 | rcu_read_lock(); | ||
402 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
403 | |||
404 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
405 | printk(KERN_DEBUG "%s: Added IBSS STA %pM\n", | ||
406 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
407 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
408 | |||
409 | ieee80211_queue_work(&local->hw, &local->sta_finish_work); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * On first glance, this will look racy, because the code | ||
416 | * below this point, which inserts a station with sleeping, | ||
417 | * unlocks the sta_lock between checking existence in the | ||
418 | * hash table and inserting into it. | ||
419 | * | ||
420 | * However, it is not racy against itself because it keeps | ||
421 | * the mutex locked. It still seems to race against the | ||
422 | * above code that atomically inserts the station... That, | ||
423 | * however, is not true because the above code can only | ||
424 | * be invoked for IBSS interfaces, and the below code will | ||
425 | * not be -- and the two do not race against each other as | ||
426 | * the hash table also keys off the interface. | ||
427 | */ | ||
428 | |||
429 | might_sleep(); | ||
430 | |||
431 | mutex_lock(&local->sta_mtx); | ||
432 | |||
403 | spin_lock_irqsave(&local->sta_lock, flags); | 433 | spin_lock_irqsave(&local->sta_lock, flags); |
404 | /* check if STA exists already */ | 434 | /* check if STA exists already */ |
405 | if (sta_info_get(sdata, sta->sta.addr)) { | 435 | if (sta_info_get_bss(sdata, sta->sta.addr)) { |
406 | spin_unlock_irqrestore(&local->sta_lock, flags); | 436 | spin_unlock_irqrestore(&local->sta_lock, flags); |
437 | rcu_read_lock(); | ||
407 | err = -EEXIST; | 438 | err = -EEXIST; |
408 | goto out_free; | 439 | goto out_free; |
409 | } | 440 | } |
410 | list_add(&sta->list, &local->sta_list); | ||
411 | local->sta_generation++; | ||
412 | local->num_sta++; | ||
413 | sta_info_hash_add(local, sta); | ||
414 | 441 | ||
415 | /* notify driver */ | 442 | spin_unlock_irqrestore(&local->sta_lock, flags); |
416 | if (local->ops->sta_notify) { | ||
417 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
418 | sdata = container_of(sdata->bss, | ||
419 | struct ieee80211_sub_if_data, | ||
420 | u.ap); | ||
421 | 443 | ||
422 | drv_sta_notify(local, sdata, STA_NOTIFY_ADD, &sta->sta); | 444 | err = sta_info_finish_insert(sta, false); |
423 | sdata = sta->sdata; | 445 | if (err) { |
446 | mutex_unlock(&local->sta_mtx); | ||
447 | rcu_read_lock(); | ||
448 | goto out_free; | ||
424 | } | 449 | } |
425 | 450 | ||
426 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 451 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -428,22 +453,9 @@ int sta_info_insert(struct sta_info *sta) | |||
428 | wiphy_name(local->hw.wiphy), sta->sta.addr); | 453 | wiphy_name(local->hw.wiphy), sta->sta.addr); |
429 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 454 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
430 | 455 | ||
431 | spin_unlock_irqrestore(&local->sta_lock, flags); | 456 | /* move reference to rcu-protected */ |
432 | 457 | rcu_read_lock(); | |
433 | sinfo.filled = 0; | 458 | mutex_unlock(&local->sta_mtx); |
434 | sinfo.generation = local->sta_generation; | ||
435 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_ATOMIC); | ||
436 | |||
437 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
438 | /* | ||
439 | * Debugfs entry adding might sleep, so schedule process | ||
440 | * context task for adding entry for STAs that do not yet | ||
441 | * have one. | ||
442 | * NOTE: due to auto-freeing semantics this may only be done | ||
443 | * if the insertion is successful! | ||
444 | */ | ||
445 | schedule_work(&local->sta_debugfs_add); | ||
446 | #endif | ||
447 | 459 | ||
448 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 460 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
449 | mesh_accept_plinks_update(sdata); | 461 | mesh_accept_plinks_update(sdata); |
@@ -455,6 +467,15 @@ int sta_info_insert(struct sta_info *sta) | |||
455 | return err; | 467 | return err; |
456 | } | 468 | } |
457 | 469 | ||
470 | int sta_info_insert(struct sta_info *sta) | ||
471 | { | ||
472 | int err = sta_info_insert_rcu(sta); | ||
473 | |||
474 | rcu_read_unlock(); | ||
475 | |||
476 | return err; | ||
477 | } | ||
478 | |||
458 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 479 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |
459 | { | 480 | { |
460 | /* | 481 | /* |
@@ -523,108 +544,6 @@ void sta_info_clear_tim_bit(struct sta_info *sta) | |||
523 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | 544 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
524 | } | 545 | } |
525 | 546 | ||
526 | static void __sta_info_unlink(struct sta_info **sta) | ||
527 | { | ||
528 | struct ieee80211_local *local = (*sta)->local; | ||
529 | struct ieee80211_sub_if_data *sdata = (*sta)->sdata; | ||
530 | /* | ||
531 | * pull caller's reference if we're already gone. | ||
532 | */ | ||
533 | if (sta_info_hash_del(local, *sta)) { | ||
534 | *sta = NULL; | ||
535 | return; | ||
536 | } | ||
537 | |||
538 | if ((*sta)->key) { | ||
539 | ieee80211_key_free((*sta)->key); | ||
540 | WARN_ON((*sta)->key); | ||
541 | } | ||
542 | |||
543 | list_del(&(*sta)->list); | ||
544 | (*sta)->dead = true; | ||
545 | |||
546 | if (test_and_clear_sta_flags(*sta, | ||
547 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
548 | BUG_ON(!sdata->bss); | ||
549 | |||
550 | atomic_dec(&sdata->bss->num_sta_ps); | ||
551 | __sta_info_clear_tim_bit(sdata->bss, *sta); | ||
552 | } | ||
553 | |||
554 | local->num_sta--; | ||
555 | local->sta_generation++; | ||
556 | |||
557 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
558 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
559 | |||
560 | if (local->ops->sta_notify) { | ||
561 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
562 | sdata = container_of(sdata->bss, | ||
563 | struct ieee80211_sub_if_data, | ||
564 | u.ap); | ||
565 | |||
566 | drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE, | ||
567 | &(*sta)->sta); | ||
568 | sdata = (*sta)->sdata; | ||
569 | } | ||
570 | |||
571 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
572 | mesh_accept_plinks_update(sdata); | ||
573 | #ifdef CONFIG_MAC80211_MESH | ||
574 | del_timer(&(*sta)->plink_timer); | ||
575 | #endif | ||
576 | } | ||
577 | |||
578 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
579 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | ||
580 | wiphy_name(local->hw.wiphy), (*sta)->sta.addr); | ||
581 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
582 | |||
583 | /* | ||
584 | * Finally, pull caller's reference if the STA is pinned by the | ||
585 | * task that is adding the debugfs entries. In that case, we | ||
586 | * leave the STA "to be freed". | ||
587 | * | ||
588 | * The rules are not trivial, but not too complex either: | ||
589 | * (1) pin_status is only modified under the sta_lock | ||
590 | * (2) STAs may only be pinned under the RTNL so that | ||
591 | * sta_info_flush() is guaranteed to actually destroy | ||
592 | * all STAs that are active for a given interface, this | ||
593 | * is required for correctness because otherwise we | ||
594 | * could notify a driver that an interface is going | ||
595 | * away and only after that (!) notify it about a STA | ||
596 | * on that interface going away. | ||
597 | * (3) sta_info_debugfs_add_work() will set the status | ||
598 | * to PINNED when it found an item that needs a new | ||
599 | * debugfs directory created. In that case, that item | ||
600 | * must not be freed although all *RCU* users are done | ||
601 | * with it. Hence, we tell the caller of _unlink() | ||
602 | * that the item is already gone (as can happen when | ||
603 | * two tasks try to unlink/destroy at the same time) | ||
604 | * (4) We set the pin_status to DESTROY here when we | ||
605 | * find such an item. | ||
606 | * (5) sta_info_debugfs_add_work() will reset the pin_status | ||
607 | * from PINNED to NORMAL when it is done with the item, | ||
608 | * but will check for DESTROY before resetting it in | ||
609 | * which case it will free the item. | ||
610 | */ | ||
611 | if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { | ||
612 | (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; | ||
613 | *sta = NULL; | ||
614 | return; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | void sta_info_unlink(struct sta_info **sta) | ||
619 | { | ||
620 | struct ieee80211_local *local = (*sta)->local; | ||
621 | unsigned long flags; | ||
622 | |||
623 | spin_lock_irqsave(&local->sta_lock, flags); | ||
624 | __sta_info_unlink(sta); | ||
625 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
626 | } | ||
627 | |||
628 | static int sta_info_buffer_expired(struct sta_info *sta, | 547 | static int sta_info_buffer_expired(struct sta_info *sta, |
629 | struct sk_buff *skb) | 548 | struct sk_buff *skb) |
630 | { | 549 | { |
@@ -681,109 +600,209 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
681 | } | 600 | } |
682 | } | 601 | } |
683 | 602 | ||
684 | 603 | static int __must_check __sta_info_destroy(struct sta_info *sta) | |
685 | static void sta_info_cleanup(unsigned long data) | ||
686 | { | 604 | { |
687 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 605 | struct ieee80211_local *local; |
688 | struct sta_info *sta; | 606 | struct ieee80211_sub_if_data *sdata; |
607 | struct sk_buff *skb; | ||
608 | unsigned long flags; | ||
609 | int ret, i; | ||
689 | 610 | ||
690 | rcu_read_lock(); | 611 | might_sleep(); |
691 | list_for_each_entry_rcu(sta, &local->sta_list, list) | ||
692 | sta_info_cleanup_expire_buffered(local, sta); | ||
693 | rcu_read_unlock(); | ||
694 | 612 | ||
695 | if (local->quiescing) | 613 | if (!sta) |
696 | return; | 614 | return -ENOENT; |
697 | 615 | ||
698 | local->sta_cleanup.expires = | 616 | local = sta->local; |
699 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 617 | sdata = sta->sdata; |
700 | add_timer(&local->sta_cleanup); | ||
701 | } | ||
702 | 618 | ||
703 | #ifdef CONFIG_MAC80211_DEBUGFS | 619 | spin_lock_irqsave(&local->sta_lock, flags); |
704 | /* | 620 | ret = sta_info_hash_del(local, sta); |
705 | * See comment in __sta_info_unlink, | 621 | /* this might still be the pending list ... which is fine */ |
706 | * caller must hold local->sta_lock. | 622 | if (!ret) |
707 | */ | 623 | list_del(&sta->list); |
708 | static void __sta_info_pin(struct sta_info *sta) | 624 | spin_unlock_irqrestore(&local->sta_lock, flags); |
709 | { | 625 | if (ret) |
710 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); | 626 | return ret; |
711 | sta->pin_status = STA_INFO_PIN_STAT_PINNED; | 627 | |
628 | if (sta->key) { | ||
629 | ieee80211_key_free(sta->key); | ||
630 | /* | ||
631 | * We have only unlinked the key, and actually destroying it | ||
632 | * may mean it is removed from hardware which requires that | ||
633 | * the key->sta pointer is still valid, so flush the key todo | ||
634 | * list here. | ||
635 | * | ||
636 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
637 | * nothing can reference this sta struct any more. | ||
638 | */ | ||
639 | ieee80211_key_todo(); | ||
640 | |||
641 | WARN_ON(sta->key); | ||
642 | } | ||
643 | |||
644 | sta->dead = true; | ||
645 | |||
646 | if (test_and_clear_sta_flags(sta, | ||
647 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
648 | BUG_ON(!sdata->bss); | ||
649 | |||
650 | atomic_dec(&sdata->bss->num_sta_ps); | ||
651 | __sta_info_clear_tim_bit(sdata->bss, sta); | ||
652 | } | ||
653 | |||
654 | local->num_sta--; | ||
655 | local->sta_generation++; | ||
656 | |||
657 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
658 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
659 | |||
660 | if (sta->uploaded) { | ||
661 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
662 | sdata = container_of(sdata->bss, | ||
663 | struct ieee80211_sub_if_data, | ||
664 | u.ap); | ||
665 | drv_sta_remove(local, sdata, &sta->sta); | ||
666 | sdata = sta->sdata; | ||
667 | } | ||
668 | |||
669 | #ifdef CONFIG_MAC80211_MESH | ||
670 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
671 | mesh_accept_plinks_update(sdata); | ||
672 | del_timer(&sta->plink_timer); | ||
673 | } | ||
674 | #endif | ||
675 | |||
676 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
677 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | ||
678 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
679 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
680 | cancel_work_sync(&sta->drv_unblock_wk); | ||
681 | |||
682 | rate_control_remove_sta_debugfs(sta); | ||
683 | ieee80211_sta_debugfs_remove(sta); | ||
684 | |||
685 | #ifdef CONFIG_MAC80211_MESH | ||
686 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | ||
687 | mesh_plink_deactivate(sta); | ||
688 | del_timer_sync(&sta->plink_timer); | ||
689 | } | ||
690 | #endif | ||
691 | |||
692 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
693 | local->total_ps_buffered--; | ||
694 | dev_kfree_skb_any(skb); | ||
695 | } | ||
696 | |||
697 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
698 | dev_kfree_skb_any(skb); | ||
699 | |||
700 | for (i = 0; i < STA_TID_NUM; i++) { | ||
701 | struct tid_ampdu_rx *tid_rx; | ||
702 | struct tid_ampdu_tx *tid_tx; | ||
703 | |||
704 | spin_lock_bh(&sta->lock); | ||
705 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
706 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
707 | if (tid_rx) | ||
708 | tid_rx->shutdown = true; | ||
709 | |||
710 | spin_unlock_bh(&sta->lock); | ||
711 | |||
712 | /* | ||
713 | * Outside spinlock - shutdown is true now so that the timer | ||
714 | * won't free tid_rx, we have to do that now. Can't let the | ||
715 | * timer do it because we have to sync the timer outside the | ||
716 | * lock that it takes itself. | ||
717 | */ | ||
718 | if (tid_rx) { | ||
719 | del_timer_sync(&tid_rx->session_timer); | ||
720 | kfree(tid_rx); | ||
721 | } | ||
722 | |||
723 | /* | ||
724 | * No need to do such complications for TX agg sessions, the | ||
725 | * path leading to freeing the tid_tx struct goes via a call | ||
726 | * from the driver, and thus needs to look up the sta struct | ||
727 | * again, which cannot be found when we get here. Hence, we | ||
728 | * just need to delete the timer and free the aggregation | ||
729 | * info; we won't be telling the peer about it then but that | ||
730 | * doesn't matter if we're not talking to it again anyway. | ||
731 | */ | ||
732 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
733 | if (tid_tx) { | ||
734 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
735 | /* | ||
736 | * STA removed while aggregation session being | ||
737 | * started? Bit odd, but purge frames anyway. | ||
738 | */ | ||
739 | skb_queue_purge(&tid_tx->pending); | ||
740 | kfree(tid_tx); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | __sta_info_free(local, sta); | ||
745 | |||
746 | return 0; | ||
712 | } | 747 | } |
713 | 748 | ||
714 | /* | 749 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) |
715 | * See comment in __sta_info_unlink, returns sta if it | ||
716 | * needs to be destroyed. | ||
717 | */ | ||
718 | static struct sta_info *__sta_info_unpin(struct sta_info *sta) | ||
719 | { | 750 | { |
720 | struct sta_info *ret = NULL; | 751 | struct sta_info *sta; |
721 | unsigned long flags; | 752 | int ret; |
722 | 753 | ||
723 | spin_lock_irqsave(&sta->local->sta_lock, flags); | 754 | mutex_lock(&sdata->local->sta_mtx); |
724 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && | 755 | sta = sta_info_get(sdata, addr); |
725 | sta->pin_status != STA_INFO_PIN_STAT_PINNED); | 756 | ret = __sta_info_destroy(sta); |
726 | if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) | 757 | mutex_unlock(&sdata->local->sta_mtx); |
727 | ret = sta; | ||
728 | sta->pin_status = STA_INFO_PIN_STAT_NORMAL; | ||
729 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | ||
730 | 758 | ||
731 | return ret; | 759 | return ret; |
732 | } | 760 | } |
733 | 761 | ||
734 | static void sta_info_debugfs_add_work(struct work_struct *work) | 762 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
763 | const u8 *addr) | ||
735 | { | 764 | { |
736 | struct ieee80211_local *local = | 765 | struct sta_info *sta; |
737 | container_of(work, struct ieee80211_local, sta_debugfs_add); | 766 | int ret; |
738 | struct sta_info *sta, *tmp; | ||
739 | unsigned long flags; | ||
740 | 767 | ||
741 | /* We need to keep the RTNL across the whole pinned status. */ | 768 | mutex_lock(&sdata->local->sta_mtx); |
742 | rtnl_lock(); | 769 | sta = sta_info_get_bss(sdata, addr); |
743 | while (1) { | 770 | ret = __sta_info_destroy(sta); |
744 | sta = NULL; | 771 | mutex_unlock(&sdata->local->sta_mtx); |
745 | 772 | ||
746 | spin_lock_irqsave(&local->sta_lock, flags); | 773 | return ret; |
747 | list_for_each_entry(tmp, &local->sta_list, list) { | 774 | } |
748 | /* | ||
749 | * debugfs.add_has_run will be set by | ||
750 | * ieee80211_sta_debugfs_add regardless | ||
751 | * of what else it does. | ||
752 | */ | ||
753 | if (!tmp->debugfs.add_has_run) { | ||
754 | sta = tmp; | ||
755 | __sta_info_pin(sta); | ||
756 | break; | ||
757 | } | ||
758 | } | ||
759 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
760 | 775 | ||
761 | if (!sta) | 776 | static void sta_info_cleanup(unsigned long data) |
762 | break; | 777 | { |
778 | struct ieee80211_local *local = (struct ieee80211_local *) data; | ||
779 | struct sta_info *sta; | ||
780 | |||
781 | rcu_read_lock(); | ||
782 | list_for_each_entry_rcu(sta, &local->sta_list, list) | ||
783 | sta_info_cleanup_expire_buffered(local, sta); | ||
784 | rcu_read_unlock(); | ||
763 | 785 | ||
764 | ieee80211_sta_debugfs_add(sta); | 786 | if (local->quiescing) |
765 | rate_control_add_sta_debugfs(sta); | 787 | return; |
766 | 788 | ||
767 | sta = __sta_info_unpin(sta); | 789 | local->sta_cleanup.expires = |
768 | sta_info_destroy(sta); | 790 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
769 | } | 791 | add_timer(&local->sta_cleanup); |
770 | rtnl_unlock(); | ||
771 | } | 792 | } |
772 | #endif | ||
773 | 793 | ||
774 | void sta_info_init(struct ieee80211_local *local) | 794 | void sta_info_init(struct ieee80211_local *local) |
775 | { | 795 | { |
776 | spin_lock_init(&local->sta_lock); | 796 | spin_lock_init(&local->sta_lock); |
797 | mutex_init(&local->sta_mtx); | ||
777 | INIT_LIST_HEAD(&local->sta_list); | 798 | INIT_LIST_HEAD(&local->sta_list); |
799 | INIT_LIST_HEAD(&local->sta_pending_list); | ||
800 | INIT_WORK(&local->sta_finish_work, sta_info_finish_work); | ||
778 | 801 | ||
779 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 802 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
780 | (unsigned long)local); | 803 | (unsigned long)local); |
781 | local->sta_cleanup.expires = | 804 | local->sta_cleanup.expires = |
782 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 805 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
783 | |||
784 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
785 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); | ||
786 | #endif | ||
787 | } | 806 | } |
788 | 807 | ||
789 | int sta_info_start(struct ieee80211_local *local) | 808 | int sta_info_start(struct ieee80211_local *local) |
@@ -795,16 +814,6 @@ int sta_info_start(struct ieee80211_local *local) | |||
795 | void sta_info_stop(struct ieee80211_local *local) | 814 | void sta_info_stop(struct ieee80211_local *local) |
796 | { | 815 | { |
797 | del_timer(&local->sta_cleanup); | 816 | del_timer(&local->sta_cleanup); |
798 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
799 | /* | ||
800 | * Make sure the debugfs adding work isn't pending after this | ||
801 | * because we're about to be destroyed. It doesn't matter | ||
802 | * whether it ran or not since we're going to flush all STAs | ||
803 | * anyway. | ||
804 | */ | ||
805 | cancel_work_sync(&local->sta_debugfs_add); | ||
806 | #endif | ||
807 | |||
808 | sta_info_flush(local, NULL); | 817 | sta_info_flush(local, NULL); |
809 | } | 818 | } |
810 | 819 | ||
@@ -820,26 +829,19 @@ int sta_info_flush(struct ieee80211_local *local, | |||
820 | struct ieee80211_sub_if_data *sdata) | 829 | struct ieee80211_sub_if_data *sdata) |
821 | { | 830 | { |
822 | struct sta_info *sta, *tmp; | 831 | struct sta_info *sta, *tmp; |
823 | LIST_HEAD(tmp_list); | ||
824 | int ret = 0; | 832 | int ret = 0; |
825 | unsigned long flags; | ||
826 | 833 | ||
827 | might_sleep(); | 834 | might_sleep(); |
828 | 835 | ||
829 | spin_lock_irqsave(&local->sta_lock, flags); | 836 | mutex_lock(&local->sta_mtx); |
837 | |||
838 | sta_info_finish_pending(local); | ||
839 | |||
830 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 840 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
831 | if (!sdata || sdata == sta->sdata) { | 841 | if (!sdata || sdata == sta->sdata) |
832 | __sta_info_unlink(&sta); | 842 | WARN_ON(__sta_info_destroy(sta)); |
833 | if (sta) { | ||
834 | list_add_tail(&sta->list, &tmp_list); | ||
835 | ret++; | ||
836 | } | ||
837 | } | ||
838 | } | 843 | } |
839 | spin_unlock_irqrestore(&local->sta_lock, flags); | 844 | mutex_unlock(&local->sta_mtx); |
840 | |||
841 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
842 | sta_info_destroy(sta); | ||
843 | 845 | ||
844 | return ret; | 846 | return ret; |
845 | } | 847 | } |
@@ -849,24 +851,17 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
849 | { | 851 | { |
850 | struct ieee80211_local *local = sdata->local; | 852 | struct ieee80211_local *local = sdata->local; |
851 | struct sta_info *sta, *tmp; | 853 | struct sta_info *sta, *tmp; |
852 | LIST_HEAD(tmp_list); | ||
853 | unsigned long flags; | ||
854 | 854 | ||
855 | spin_lock_irqsave(&local->sta_lock, flags); | 855 | mutex_lock(&local->sta_mtx); |
856 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 856 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
857 | if (time_after(jiffies, sta->last_rx + exp_time)) { | 857 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
858 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 858 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
859 | printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", | 859 | printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", |
860 | sdata->name, sta->sta.addr); | 860 | sdata->name, sta->sta.addr); |
861 | #endif | 861 | #endif |
862 | __sta_info_unlink(&sta); | 862 | WARN_ON(__sta_info_destroy(sta)); |
863 | if (sta) | ||
864 | list_add(&sta->list, &tmp_list); | ||
865 | } | 863 | } |
866 | spin_unlock_irqrestore(&local->sta_lock, flags); | 864 | mutex_unlock(&local->sta_mtx); |
867 | |||
868 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
869 | sta_info_destroy(sta); | ||
870 | } | 865 | } |
871 | 866 | ||
872 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, | 867 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 6f79bba5706e..822d84522937 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -42,6 +42,9 @@ | |||
42 | * be in the queues | 42 | * be in the queues |
43 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping | 43 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping |
44 | * station in power-save mode, reply when the driver unblocks. | 44 | * station in power-save mode, reply when the driver unblocks. |
45 | * @WLAN_STA_DISASSOC: Disassociation in progress. | ||
46 | * This is used to reject TX BA session requests when disassociation | ||
47 | * is in progress. | ||
45 | */ | 48 | */ |
46 | enum ieee80211_sta_info_flags { | 49 | enum ieee80211_sta_info_flags { |
47 | WLAN_STA_AUTH = 1<<0, | 50 | WLAN_STA_AUTH = 1<<0, |
@@ -57,6 +60,7 @@ enum ieee80211_sta_info_flags { | |||
57 | WLAN_STA_SUSPEND = 1<<11, | 60 | WLAN_STA_SUSPEND = 1<<11, |
58 | WLAN_STA_PS_DRIVER = 1<<12, | 61 | WLAN_STA_PS_DRIVER = 1<<12, |
59 | WLAN_STA_PSPOLL = 1<<13, | 62 | WLAN_STA_PSPOLL = 1<<13, |
63 | WLAN_STA_DISASSOC = 1<<14, | ||
60 | }; | 64 | }; |
61 | 65 | ||
62 | #define STA_TID_NUM 16 | 66 | #define STA_TID_NUM 16 |
@@ -162,11 +166,6 @@ struct sta_ampdu_mlme { | |||
162 | }; | 166 | }; |
163 | 167 | ||
164 | 168 | ||
165 | /* see __sta_info_unlink */ | ||
166 | #define STA_INFO_PIN_STAT_NORMAL 0 | ||
167 | #define STA_INFO_PIN_STAT_PINNED 1 | ||
168 | #define STA_INFO_PIN_STAT_DESTROY 2 | ||
169 | |||
170 | /** | 169 | /** |
171 | * struct sta_info - STA information | 170 | * struct sta_info - STA information |
172 | * | 171 | * |
@@ -187,7 +186,6 @@ struct sta_ampdu_mlme { | |||
187 | * @flaglock: spinlock for flags accesses | 186 | * @flaglock: spinlock for flags accesses |
188 | * @drv_unblock_wk: used for driver PS unblocking | 187 | * @drv_unblock_wk: used for driver PS unblocking |
189 | * @listen_interval: listen interval of this station, when we're acting as AP | 188 | * @listen_interval: listen interval of this station, when we're acting as AP |
190 | * @pin_status: used internally for pinning a STA struct into memory | ||
191 | * @flags: STA flags, see &enum ieee80211_sta_info_flags | 189 | * @flags: STA flags, see &enum ieee80211_sta_info_flags |
192 | * @ps_tx_buf: buffer of frames to transmit to this station | 190 | * @ps_tx_buf: buffer of frames to transmit to this station |
193 | * when it leaves power saving state | 191 | * when it leaves power saving state |
@@ -226,6 +224,7 @@ struct sta_ampdu_mlme { | |||
226 | * @debugfs: debug filesystem info | 224 | * @debugfs: debug filesystem info |
227 | * @sta: station information we share with the driver | 225 | * @sta: station information we share with the driver |
228 | * @dead: set to true when sta is unlinked | 226 | * @dead: set to true when sta is unlinked |
227 | * @uploaded: set to true when sta is uploaded to the driver | ||
229 | */ | 228 | */ |
230 | struct sta_info { | 229 | struct sta_info { |
231 | /* General information, mostly static */ | 230 | /* General information, mostly static */ |
@@ -245,11 +244,7 @@ struct sta_info { | |||
245 | 244 | ||
246 | bool dead; | 245 | bool dead; |
247 | 246 | ||
248 | /* | 247 | bool uploaded; |
249 | * for use by the internal lifetime management, | ||
250 | * see __sta_info_unlink | ||
251 | */ | ||
252 | u8 pin_status; | ||
253 | 248 | ||
254 | /* | 249 | /* |
255 | * frequently updated, locked with own spinlock (flaglock), | 250 | * frequently updated, locked with own spinlock (flaglock), |
@@ -449,18 +444,19 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
449 | * Insert STA info into hash table/list, returns zero or a | 444 | * Insert STA info into hash table/list, returns zero or a |
450 | * -EEXIST if (if the same MAC address is already present). | 445 | * -EEXIST if (if the same MAC address is already present). |
451 | * | 446 | * |
452 | * Calling this without RCU protection makes the caller | 447 | * Calling the non-rcu version makes the caller relinquish, |
453 | * relinquish its reference to @sta. | 448 | * the _rcu version calls read_lock_rcu() and must be called |
449 | * without it held. | ||
454 | */ | 450 | */ |
455 | int sta_info_insert(struct sta_info *sta); | 451 | int sta_info_insert(struct sta_info *sta); |
456 | /* | 452 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); |
457 | * Unlink a STA info from the hash table/list. | 453 | int sta_info_insert_atomic(struct sta_info *sta); |
458 | * This can NULL the STA pointer if somebody else | 454 | |
459 | * has already unlinked it. | 455 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, |
460 | */ | 456 | const u8 *addr); |
461 | void sta_info_unlink(struct sta_info **sta); | 457 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
458 | const u8 *addr); | ||
462 | 459 | ||
463 | void sta_info_destroy(struct sta_info *sta); | ||
464 | void sta_info_set_tim_bit(struct sta_info *sta); | 460 | void sta_info_set_tim_bit(struct sta_info *sta); |
465 | void sta_info_clear_tim_bit(struct sta_info *sta); | 461 | void sta_info_clear_tim_bit(struct sta_info *sta); |
466 | 462 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index e57ad6b1d7ea..ded98730c111 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -188,6 +188,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
188 | rcu_read_lock(); | 188 | rcu_read_lock(); |
189 | 189 | ||
190 | sband = local->hw.wiphy->bands[info->band]; | 190 | sband = local->hw.wiphy->bands[info->band]; |
191 | fc = hdr->frame_control; | ||
191 | 192 | ||
192 | for_each_sta_info(local, hdr->addr1, sta, tmp) { | 193 | for_each_sta_info(local, hdr->addr1, sta, tmp) { |
193 | /* skip wrong virtual interface */ | 194 | /* skip wrong virtual interface */ |
@@ -205,8 +206,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
205 | return; | 206 | return; |
206 | } | 207 | } |
207 | 208 | ||
208 | fc = hdr->frame_control; | ||
209 | |||
210 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && | 209 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && |
211 | (ieee80211_is_data_qos(fc))) { | 210 | (ieee80211_is_data_qos(fc))) { |
212 | u16 tid, ssn; | 211 | u16 tid, ssn; |
@@ -275,6 +274,20 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
275 | local->dot11FailedCount++; | 274 | local->dot11FailedCount++; |
276 | } | 275 | } |
277 | 276 | ||
277 | if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) && | ||
278 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && | ||
279 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && | ||
280 | local->ps_sdata && !(local->scanning)) { | ||
281 | if (info->flags & IEEE80211_TX_STAT_ACK) { | ||
282 | local->ps_sdata->u.mgd.flags |= | ||
283 | IEEE80211_STA_NULLFUNC_ACKED; | ||
284 | ieee80211_queue_work(&local->hw, | ||
285 | &local->dynamic_ps_enable_work); | ||
286 | } else | ||
287 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
288 | msecs_to_jiffies(10)); | ||
289 | } | ||
290 | |||
278 | /* this was a transmitted frame, but now we want to reuse it */ | 291 | /* this was a transmitted frame, but now we want to reuse it */ |
279 | skb_orphan(skb); | 292 | skb_orphan(skb); |
280 | 293 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 85e382aa894e..cbe53ed4fb0b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -571,7 +571,7 @@ ieee80211_tx_h_sta(struct ieee80211_tx_data *tx) | |||
571 | { | 571 | { |
572 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 572 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
573 | 573 | ||
574 | if (tx->sta) | 574 | if (tx->sta && tx->sta->uploaded) |
575 | info->control.sta = &tx->sta->sta; | 575 | info->control.sta = &tx->sta->sta; |
576 | 576 | ||
577 | return TX_CONTINUE; | 577 | return TX_CONTINUE; |
@@ -1010,7 +1010,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1010 | (struct ieee80211_radiotap_header *) skb->data; | 1010 | (struct ieee80211_radiotap_header *) skb->data; |
1011 | struct ieee80211_supported_band *sband; | 1011 | struct ieee80211_supported_band *sband; |
1012 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1012 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1013 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); | 1013 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, |
1014 | NULL); | ||
1014 | 1015 | ||
1015 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; | 1016 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; |
1016 | 1017 | ||
@@ -1046,7 +1047,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1046 | * because it will be recomputed and added | 1047 | * because it will be recomputed and added |
1047 | * on transmission | 1048 | * on transmission |
1048 | */ | 1049 | */ |
1049 | if (skb->len < (iterator.max_length + FCS_LEN)) | 1050 | if (skb->len < (iterator._max_length + FCS_LEN)) |
1050 | return false; | 1051 | return false; |
1051 | 1052 | ||
1052 | skb_trim(skb, skb->len - FCS_LEN); | 1053 | skb_trim(skb, skb->len - FCS_LEN); |
@@ -1073,10 +1074,10 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1073 | 1074 | ||
1074 | /* | 1075 | /* |
1075 | * remove the radiotap header | 1076 | * remove the radiotap header |
1076 | * iterator->max_length was sanity-checked against | 1077 | * iterator->_max_length was sanity-checked against |
1077 | * skb->len by iterator init | 1078 | * skb->len by iterator init |
1078 | */ | 1079 | */ |
1079 | skb_pull(skb, iterator.max_length); | 1080 | skb_pull(skb, iterator._max_length); |
1080 | 1081 | ||
1081 | return true; | 1082 | return true; |
1082 | } | 1083 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ca170b417da6..c453226f06b2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1082,7 +1082,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1082 | struct ieee80211_hw *hw = &local->hw; | 1082 | struct ieee80211_hw *hw = &local->hw; |
1083 | struct ieee80211_sub_if_data *sdata; | 1083 | struct ieee80211_sub_if_data *sdata; |
1084 | struct sta_info *sta; | 1084 | struct sta_info *sta; |
1085 | unsigned long flags; | ||
1086 | int res; | 1085 | int res; |
1087 | 1086 | ||
1088 | if (local->suspended) | 1087 | if (local->suspended) |
@@ -1116,20 +1115,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1116 | } | 1115 | } |
1117 | 1116 | ||
1118 | /* add STAs back */ | 1117 | /* add STAs back */ |
1119 | if (local->ops->sta_notify) { | 1118 | mutex_lock(&local->sta_mtx); |
1120 | spin_lock_irqsave(&local->sta_lock, flags); | 1119 | list_for_each_entry(sta, &local->sta_list, list) { |
1121 | list_for_each_entry(sta, &local->sta_list, list) { | 1120 | if (sta->uploaded) { |
1122 | sdata = sta->sdata; | 1121 | sdata = sta->sdata; |
1123 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1122 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
1124 | sdata = container_of(sdata->bss, | 1123 | sdata = container_of(sdata->bss, |
1125 | struct ieee80211_sub_if_data, | 1124 | struct ieee80211_sub_if_data, |
1126 | u.ap); | 1125 | u.ap); |
1127 | 1126 | ||
1128 | drv_sta_notify(local, sdata, STA_NOTIFY_ADD, | 1127 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); |
1129 | &sta->sta); | ||
1130 | } | 1128 | } |
1131 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1132 | } | 1129 | } |
1130 | mutex_unlock(&local->sta_mtx); | ||
1133 | 1131 | ||
1134 | /* Clear Suspend state so that ADDBA requests can be processed */ | 1132 | /* Clear Suspend state so that ADDBA requests can be processed */ |
1135 | 1133 | ||
@@ -1180,6 +1178,14 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1180 | } | 1178 | } |
1181 | } | 1179 | } |
1182 | 1180 | ||
1181 | rcu_read_lock(); | ||
1182 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
1183 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
1184 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
1185 | } | ||
1186 | } | ||
1187 | rcu_read_unlock(); | ||
1188 | |||
1183 | /* add back keys */ | 1189 | /* add back keys */ |
1184 | list_for_each_entry(sdata, &local->interfaces, list) | 1190 | list_for_each_entry(sdata, &local->interfaces, list) |
1185 | if (ieee80211_sdata_running(sdata)) | 1191 | if (ieee80211_sdata_running(sdata)) |
@@ -1219,10 +1225,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1219 | 1225 | ||
1220 | add_timer(&local->sta_cleanup); | 1226 | add_timer(&local->sta_cleanup); |
1221 | 1227 | ||
1222 | spin_lock_irqsave(&local->sta_lock, flags); | 1228 | mutex_lock(&local->sta_mtx); |
1223 | list_for_each_entry(sta, &local->sta_list, list) | 1229 | list_for_each_entry(sta, &local->sta_list, list) |
1224 | mesh_plink_restart(sta); | 1230 | mesh_plink_restart(sta); |
1225 | spin_unlock_irqrestore(&local->sta_lock, flags); | 1231 | mutex_unlock(&local->sta_mtx); |
1226 | #else | 1232 | #else |
1227 | WARN_ON(1); | 1233 | WARN_ON(1); |
1228 | #endif | 1234 | #endif |