diff options
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r-- | net/mac80211/ieee80211.c | 78 |
1 files changed, 52 insertions, 26 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 727af295c969..85b1391375c0 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -375,15 +375,19 @@ static int ieee80211_stop(struct net_device *dev) | |||
375 | 375 | ||
376 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 376 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
377 | 377 | ||
378 | list_for_each_entry(sta, &local->sta_list, list) { | 378 | rcu_read_lock(); |
379 | if (sta->dev == dev) | 379 | |
380 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
381 | if (sta->sdata == sdata) | ||
380 | for (i = 0; i < STA_TID_NUM; i++) | 382 | for (i = 0; i < STA_TID_NUM; i++) |
381 | ieee80211_sta_stop_rx_ba_session(sta->dev, | 383 | ieee80211_sta_stop_rx_ba_session(sdata->dev, |
382 | sta->addr, i, | 384 | sta->addr, i, |
383 | WLAN_BACK_RECIPIENT, | 385 | WLAN_BACK_RECIPIENT, |
384 | WLAN_REASON_QSTA_LEAVE_QBSS); | 386 | WLAN_REASON_QSTA_LEAVE_QBSS); |
385 | } | 387 | } |
386 | 388 | ||
389 | rcu_read_unlock(); | ||
390 | |||
387 | netif_stop_queue(dev); | 391 | netif_stop_queue(dev); |
388 | 392 | ||
389 | /* | 393 | /* |
@@ -449,7 +453,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
449 | netif_tx_unlock_bh(local->mdev); | 453 | netif_tx_unlock_bh(local->mdev); |
450 | break; | 454 | break; |
451 | case IEEE80211_IF_TYPE_MESH_POINT: | 455 | case IEEE80211_IF_TYPE_MESH_POINT: |
452 | sta_info_flush(local, dev); | 456 | sta_info_flush(local, sdata); |
453 | /* fall through */ | 457 | /* fall through */ |
454 | case IEEE80211_IF_TYPE_STA: | 458 | case IEEE80211_IF_TYPE_STA: |
455 | case IEEE80211_IF_TYPE_IBSS: | 459 | case IEEE80211_IF_TYPE_IBSS: |
@@ -522,9 +526,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
522 | print_mac(mac, ra), tid); | 526 | print_mac(mac, ra), tid); |
523 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 527 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
524 | 528 | ||
529 | rcu_read_lock(); | ||
530 | |||
525 | sta = sta_info_get(local, ra); | 531 | sta = sta_info_get(local, ra); |
526 | if (!sta) { | 532 | if (!sta) { |
527 | printk(KERN_DEBUG "Could not find the station\n"); | 533 | printk(KERN_DEBUG "Could not find the station\n"); |
534 | rcu_read_unlock(); | ||
528 | return -ENOENT; | 535 | return -ENOENT; |
529 | } | 536 | } |
530 | 537 | ||
@@ -564,7 +571,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
564 | spin_unlock_bh(&local->mdev->queue_lock); | 571 | spin_unlock_bh(&local->mdev->queue_lock); |
565 | goto start_ba_exit; | 572 | goto start_ba_exit; |
566 | } | 573 | } |
567 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 574 | sdata = sta->sdata; |
568 | 575 | ||
569 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | 576 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the |
570 | * call back right away, it must see that the flow has begun */ | 577 | * call back right away, it must see that the flow has begun */ |
@@ -601,7 +608,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
601 | sta->ampdu_mlme.dialog_token_allocator; | 608 | sta->ampdu_mlme.dialog_token_allocator; |
602 | sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; | 609 | sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; |
603 | 610 | ||
604 | ieee80211_send_addba_request(sta->dev, ra, tid, | 611 | ieee80211_send_addba_request(sta->sdata->dev, ra, tid, |
605 | sta->ampdu_mlme.tid_tx[tid].dialog_token, | 612 | sta->ampdu_mlme.tid_tx[tid].dialog_token, |
606 | sta->ampdu_mlme.tid_tx[tid].ssn, | 613 | sta->ampdu_mlme.tid_tx[tid].ssn, |
607 | 0x40, 5000); | 614 | 0x40, 5000); |
@@ -614,7 +621,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
614 | 621 | ||
615 | start_ba_exit: | 622 | start_ba_exit: |
616 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 623 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
617 | sta_info_put(sta); | 624 | rcu_read_unlock(); |
618 | return ret; | 625 | return ret; |
619 | } | 626 | } |
620 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | 627 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); |
@@ -637,9 +644,12 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | |||
637 | print_mac(mac, ra), tid); | 644 | print_mac(mac, ra), tid); |
638 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 645 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
639 | 646 | ||
647 | rcu_read_lock(); | ||
640 | sta = sta_info_get(local, ra); | 648 | sta = sta_info_get(local, ra); |
641 | if (!sta) | 649 | if (!sta) { |
650 | rcu_read_unlock(); | ||
642 | return -ENOENT; | 651 | return -ENOENT; |
652 | } | ||
643 | 653 | ||
644 | /* check if the TID is in aggregation */ | 654 | /* check if the TID is in aggregation */ |
645 | state = &sta->ampdu_mlme.tid_tx[tid].state; | 655 | state = &sta->ampdu_mlme.tid_tx[tid].state; |
@@ -673,7 +683,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, | |||
673 | 683 | ||
674 | stop_BA_exit: | 684 | stop_BA_exit: |
675 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 685 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
676 | sta_info_put(sta); | 686 | rcu_read_unlock(); |
677 | return ret; | 687 | return ret; |
678 | } | 688 | } |
679 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | 689 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); |
@@ -691,8 +701,10 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
691 | return; | 701 | return; |
692 | } | 702 | } |
693 | 703 | ||
704 | rcu_read_lock(); | ||
694 | sta = sta_info_get(local, ra); | 705 | sta = sta_info_get(local, ra); |
695 | if (!sta) { | 706 | if (!sta) { |
707 | rcu_read_unlock(); | ||
696 | printk(KERN_DEBUG "Could not find station: %s\n", | 708 | printk(KERN_DEBUG "Could not find station: %s\n", |
697 | print_mac(mac, ra)); | 709 | print_mac(mac, ra)); |
698 | return; | 710 | return; |
@@ -705,7 +717,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
705 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | 717 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", |
706 | *state); | 718 | *state); |
707 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 719 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
708 | sta_info_put(sta); | 720 | rcu_read_unlock(); |
709 | return; | 721 | return; |
710 | } | 722 | } |
711 | 723 | ||
@@ -718,7 +730,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
718 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 730 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); |
719 | } | 731 | } |
720 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 732 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
721 | sta_info_put(sta); | 733 | rcu_read_unlock(); |
722 | } | 734 | } |
723 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); | 735 | EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); |
724 | 736 | ||
@@ -739,10 +751,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
739 | printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", | 751 | printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", |
740 | print_mac(mac, ra), tid); | 752 | print_mac(mac, ra), tid); |
741 | 753 | ||
754 | rcu_read_lock(); | ||
742 | sta = sta_info_get(local, ra); | 755 | sta = sta_info_get(local, ra); |
743 | if (!sta) { | 756 | if (!sta) { |
744 | printk(KERN_DEBUG "Could not find station: %s\n", | 757 | printk(KERN_DEBUG "Could not find station: %s\n", |
745 | print_mac(mac, ra)); | 758 | print_mac(mac, ra)); |
759 | rcu_read_unlock(); | ||
746 | return; | 760 | return; |
747 | } | 761 | } |
748 | state = &sta->ampdu_mlme.tid_tx[tid].state; | 762 | state = &sta->ampdu_mlme.tid_tx[tid].state; |
@@ -750,13 +764,13 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
750 | spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); | 764 | spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); |
751 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { | 765 | if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { |
752 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); | 766 | printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); |
753 | sta_info_put(sta); | ||
754 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 767 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
768 | rcu_read_unlock(); | ||
755 | return; | 769 | return; |
756 | } | 770 | } |
757 | 771 | ||
758 | if (*state & HT_AGG_STATE_INITIATOR_MSK) | 772 | if (*state & HT_AGG_STATE_INITIATOR_MSK) |
759 | ieee80211_send_delba(sta->dev, ra, tid, | 773 | ieee80211_send_delba(sta->sdata->dev, ra, tid, |
760 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | 774 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
761 | 775 | ||
762 | agg_queue = sta->tid_to_tx_q[tid]; | 776 | agg_queue = sta->tid_to_tx_q[tid]; |
@@ -777,7 +791,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
777 | sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; | 791 | sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; |
778 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 792 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
779 | 793 | ||
780 | sta_info_put(sta); | 794 | rcu_read_unlock(); |
781 | } | 795 | } |
782 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); | 796 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); |
783 | 797 | ||
@@ -887,32 +901,41 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) | |||
887 | struct sta_info *sta; | 901 | struct sta_info *sta; |
888 | DECLARE_MAC_BUF(mac); | 902 | DECLARE_MAC_BUF(mac); |
889 | 903 | ||
904 | might_sleep(); | ||
905 | |||
890 | if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) | 906 | if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) |
891 | return 0; | 907 | return 0; |
892 | 908 | ||
909 | rcu_read_lock(); | ||
910 | |||
893 | /* Create STA entry for the new peer */ | 911 | /* Create STA entry for the new peer */ |
894 | sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); | 912 | sta = sta_info_add(sdata, remote_addr); |
895 | if (IS_ERR(sta)) | 913 | if (IS_ERR(sta)) { |
914 | rcu_read_unlock(); | ||
896 | return PTR_ERR(sta); | 915 | return PTR_ERR(sta); |
916 | } | ||
897 | 917 | ||
898 | sta->flags |= WLAN_STA_AUTHORIZED; | 918 | sta->flags |= WLAN_STA_AUTHORIZED; |
899 | 919 | ||
900 | sta_info_put(sta); | ||
901 | |||
902 | /* Remove STA entry for the old peer */ | 920 | /* Remove STA entry for the old peer */ |
903 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | 921 | sta = sta_info_get(local, sdata->u.wds.remote_addr); |
904 | if (sta) { | 922 | if (sta) |
905 | sta_info_free(sta); | 923 | sta_info_unlink(&sta); |
906 | sta_info_put(sta); | 924 | else |
907 | } else { | ||
908 | printk(KERN_DEBUG "%s: could not find STA entry for WDS link " | 925 | printk(KERN_DEBUG "%s: could not find STA entry for WDS link " |
909 | "peer %s\n", | 926 | "peer %s\n", |
910 | dev->name, print_mac(mac, sdata->u.wds.remote_addr)); | 927 | dev->name, print_mac(mac, sdata->u.wds.remote_addr)); |
911 | } | ||
912 | 928 | ||
913 | /* Update WDS link data */ | 929 | /* Update WDS link data */ |
914 | memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); | 930 | memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); |
915 | 931 | ||
932 | rcu_read_unlock(); | ||
933 | |||
934 | if (sta) { | ||
935 | synchronize_rcu(); | ||
936 | sta_info_destroy(sta); | ||
937 | } | ||
938 | |||
916 | return 0; | 939 | return 0; |
917 | } | 940 | } |
918 | 941 | ||
@@ -1330,6 +1353,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1330 | return; | 1353 | return; |
1331 | } | 1354 | } |
1332 | 1355 | ||
1356 | rcu_read_lock(); | ||
1357 | |||
1333 | if (status->excessive_retries) { | 1358 | if (status->excessive_retries) { |
1334 | struct sta_info *sta; | 1359 | struct sta_info *sta; |
1335 | sta = sta_info_get(local, hdr->addr1); | 1360 | sta = sta_info_get(local, hdr->addr1); |
@@ -1343,10 +1368,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1343 | status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; | 1368 | status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; |
1344 | ieee80211_handle_filtered_frame(local, sta, | 1369 | ieee80211_handle_filtered_frame(local, sta, |
1345 | skb, status); | 1370 | skb, status); |
1346 | sta_info_put(sta); | 1371 | rcu_read_unlock(); |
1347 | return; | 1372 | return; |
1348 | } | 1373 | } |
1349 | sta_info_put(sta); | ||
1350 | } | 1374 | } |
1351 | } | 1375 | } |
1352 | 1376 | ||
@@ -1356,12 +1380,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1356 | if (sta) { | 1380 | if (sta) { |
1357 | ieee80211_handle_filtered_frame(local, sta, skb, | 1381 | ieee80211_handle_filtered_frame(local, sta, skb, |
1358 | status); | 1382 | status); |
1359 | sta_info_put(sta); | 1383 | rcu_read_unlock(); |
1360 | return; | 1384 | return; |
1361 | } | 1385 | } |
1362 | } else | 1386 | } else |
1363 | rate_control_tx_status(local->mdev, skb, status); | 1387 | rate_control_tx_status(local->mdev, skb, status); |
1364 | 1388 | ||
1389 | rcu_read_unlock(); | ||
1390 | |||
1365 | ieee80211_led_tx(local, 0); | 1391 | ieee80211_led_tx(local, 0); |
1366 | 1392 | ||
1367 | /* SNMP counters | 1393 | /* SNMP counters |