aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 15:30:46 -0500
commitd0709a65181beb787ef3f58cfe45536a2bb254c8 (patch)
tree29e5f36583b0e0a3f11b291347e57672eab41dad /net/mac80211/ieee80211.c
parent5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (diff)
mac80211: RCU-ify STA info structure access
This makes access to the STA hash table/list use RCU to protect against freeing of items. However, it's not a true RCU, the copy step is missing: whenever somebody changes a STA item it is simply updated. This is an existing race condition that is now somewhat understandable. This patch also fixes the race key freeing vs. STA destruction by making sure that sta_info_destroy() is always called under RTNL and frees the key. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r--net/mac80211/ieee80211.c78
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
615start_ba_exit: 622start_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}
620EXPORT_SYMBOL(ieee80211_start_tx_ba_session); 627EXPORT_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
674stop_BA_exit: 684stop_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}
679EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); 689EXPORT_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}
723EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); 735EXPORT_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}
782EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); 796EXPORT_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