aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-12-14 06:35:30 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-12-15 14:46:34 -0500
commitd9a7ddb05e5419ca5e4b54f57074dc33c7ea991c (patch)
tree3de3213e7e79a64254ea778374aeaaffa61b5bab
parent87be1e1e00f870567780dec111193426b4c085e8 (diff)
mac80211: refactor station state transitions
Station entries can have various states, the most important ones being auth, assoc and authorized. This patch prepares us for telling the driver about these states, we don't want to confuse drivers with strange transitions, so with this we enforce that they move in the right order between them (back and forth); some transitions might happen before the driver even knows about the station, but at least runtime transitions will be ordered correctly. As a consequence, IBSS and MESH stations will now have the ASSOC flag set (so they can transition to AUTHORIZED), and we can get rid of a special case in TX processing. When freeing a station, unwind the state so that other parts of the code (or drivers later) can rely on the transitions. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/cfg.c76
-rw-r--r--net/mac80211/ibss.c5
-rw-r--r--net/mac80211/iface.c5
-rw-r--r--net/mac80211/mesh_plink.c7
-rw-r--r--net/mac80211/mlme.c6
-rw-r--r--net/mac80211/sta_info.c65
-rw-r--r--net/mac80211/sta_info.h37
-rw-r--r--net/mac80211/tx.c1
8 files changed, 172 insertions, 30 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 3acda35df5cb..66ad9d9af87f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -746,10 +746,11 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
746 netif_rx_ni(skb); 746 netif_rx_ni(skb);
747} 747}
748 748
749static void sta_apply_parameters(struct ieee80211_local *local, 749static int sta_apply_parameters(struct ieee80211_local *local,
750 struct sta_info *sta, 750 struct sta_info *sta,
751 struct station_parameters *params) 751 struct station_parameters *params)
752{ 752{
753 int ret = 0;
753 u32 rates; 754 u32 rates;
754 int i, j; 755 int i, j;
755 struct ieee80211_supported_band *sband; 756 struct ieee80211_supported_band *sband;
@@ -761,13 +762,59 @@ static void sta_apply_parameters(struct ieee80211_local *local,
761 mask = params->sta_flags_mask; 762 mask = params->sta_flags_mask;
762 set = params->sta_flags_set; 763 set = params->sta_flags_set;
763 764
765 /*
766 * In mesh mode, we can clear AUTHENTICATED flag but must
767 * also make ASSOCIATED follow appropriately for the driver
768 * API. See also below, after AUTHORIZED changes.
769 */
770 if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
771 /* cfg80211 should not allow this in non-mesh modes */
772 if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
773 return -EINVAL;
774
775 if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
776 !test_sta_flag(sta, WLAN_STA_AUTH)) {
777 ret = sta_info_move_state_checked(sta,
778 IEEE80211_STA_AUTH);
779 if (ret)
780 return ret;
781 ret = sta_info_move_state_checked(sta,
782 IEEE80211_STA_ASSOC);
783 if (ret)
784 return ret;
785 }
786 }
787
764 if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { 788 if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
765 if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) 789 if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
766 set_sta_flag(sta, WLAN_STA_AUTHORIZED); 790 ret = sta_info_move_state_checked(sta,
791 IEEE80211_STA_AUTHORIZED);
767 else 792 else
768 clear_sta_flag(sta, WLAN_STA_AUTHORIZED); 793 ret = sta_info_move_state_checked(sta,
794 IEEE80211_STA_ASSOC);
795 if (ret)
796 return ret;
769 } 797 }
770 798
799 if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
800 /* cfg80211 should not allow this in non-mesh modes */
801 if (WARN_ON(!ieee80211_vif_is_mesh(&sdata->vif)))
802 return -EINVAL;
803
804 if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
805 test_sta_flag(sta, WLAN_STA_AUTH)) {
806 ret = sta_info_move_state_checked(sta,
807 IEEE80211_STA_AUTH);
808 if (ret)
809 return ret;
810 ret = sta_info_move_state_checked(sta,
811 IEEE80211_STA_NONE);
812 if (ret)
813 return ret;
814 }
815 }
816
817
771 if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { 818 if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
772 if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) 819 if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
773 set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE); 820 set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
@@ -792,13 +839,6 @@ static void sta_apply_parameters(struct ieee80211_local *local,
792 clear_sta_flag(sta, WLAN_STA_MFP); 839 clear_sta_flag(sta, WLAN_STA_MFP);
793 } 840 }
794 841
795 if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) {
796 if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
797 set_sta_flag(sta, WLAN_STA_AUTH);
798 else
799 clear_sta_flag(sta, WLAN_STA_AUTH);
800 }
801
802 if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { 842 if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
803 if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) 843 if (set & BIT(NL80211_STA_FLAG_TDLS_PEER))
804 set_sta_flag(sta, WLAN_STA_TDLS_PEER); 844 set_sta_flag(sta, WLAN_STA_TDLS_PEER);
@@ -870,6 +910,8 @@ static void sta_apply_parameters(struct ieee80211_local *local,
870 } 910 }
871#endif 911#endif
872 } 912 }
913
914 return 0;
873} 915}
874 916
875static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, 917static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
@@ -900,10 +942,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
900 if (!sta) 942 if (!sta)
901 return -ENOMEM; 943 return -ENOMEM;
902 944
903 set_sta_flag(sta, WLAN_STA_AUTH); 945 sta_info_move_state(sta, IEEE80211_STA_AUTH);
904 set_sta_flag(sta, WLAN_STA_ASSOC); 946 sta_info_move_state(sta, IEEE80211_STA_ASSOC);
905 947
906 sta_apply_parameters(local, sta, params); 948 err = sta_apply_parameters(local, sta, params);
949 if (err) {
950 sta_info_free(local, sta);
951 return err;
952 }
907 953
908 /* 954 /*
909 * for TDLS, rate control should be initialized only when supported 955 * for TDLS, rate control should be initialized only when supported
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index fe0e91e0b8bc..47e2db9133cb 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -512,7 +512,10 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
512 return NULL; 512 return NULL;
513 513
514 sta->last_rx = jiffies; 514 sta->last_rx = jiffies;
515 set_sta_flag(sta, WLAN_STA_AUTHORIZED); 515
516 sta_info_move_state(sta, IEEE80211_STA_AUTH);
517 sta_info_move_state(sta, IEEE80211_STA_ASSOC);
518 sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
516 519
517 /* make sure mandatory rates are always added */ 520 /* make sure mandatory rates are always added */
518 sta->sta.supp_rates[band] = supp_rates | 521 sta->sta.supp_rates[band] = supp_rates |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 3d3bb5e9d8fa..e47768cb8cb3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -318,8 +318,9 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
318 goto err_del_interface; 318 goto err_del_interface;
319 } 319 }
320 320
321 /* no atomic bitop required since STA is not live yet */ 321 sta_info_move_state(sta, IEEE80211_STA_AUTH);
322 set_sta_flag(sta, WLAN_STA_AUTHORIZED); 322 sta_info_move_state(sta, IEEE80211_STA_ASSOC);
323 sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
323 324
324 res = sta_info_insert(sta); 325 res = sta_info_insert(sta);
325 if (res) { 326 if (res) {
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 7314372b12ba..41ef1b476442 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -96,9 +96,12 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
96 if (!sta) 96 if (!sta)
97 return NULL; 97 return NULL;
98 98
99 set_sta_flag(sta, WLAN_STA_AUTH); 99 sta_info_move_state(sta, IEEE80211_STA_AUTH);
100 set_sta_flag(sta, WLAN_STA_AUTHORIZED); 100 sta_info_move_state(sta, IEEE80211_STA_ASSOC);
101 sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
102
101 set_sta_flag(sta, WLAN_STA_WME); 103 set_sta_flag(sta, WLAN_STA_WME);
104
102 sta->sta.supp_rates[local->hw.conf.channel->band] = rates; 105 sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
103 if (elems->ht_cap_elem) 106 if (elems->ht_cap_elem)
104 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, 107 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 09019d135942..3789b82f1098 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1577,10 +1577,10 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
1577 return false; 1577 return false;
1578 } 1578 }
1579 1579
1580 set_sta_flag(sta, WLAN_STA_AUTH); 1580 sta_info_move_state(sta, IEEE80211_STA_AUTH);
1581 set_sta_flag(sta, WLAN_STA_ASSOC); 1581 sta_info_move_state(sta, IEEE80211_STA_ASSOC);
1582 if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) 1582 if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
1583 set_sta_flag(sta, WLAN_STA_AUTHORIZED); 1583 sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
1584 1584
1585 rates = 0; 1585 rates = 0;
1586 basic_rates = 0; 1586 basic_rates = 0;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index c6ca9bd81add..b22775cdcdf5 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -204,16 +204,17 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
204} 204}
205 205
206/** 206/**
207 * __sta_info_free - internal STA free helper 207 * sta_info_free - free STA
208 * 208 *
209 * @local: pointer to the global information 209 * @local: pointer to the global information
210 * @sta: STA info to free 210 * @sta: STA info to free
211 * 211 *
212 * This function must undo everything done by sta_info_alloc() 212 * This function must undo everything done by sta_info_alloc()
213 * that may happen before sta_info_insert(). 213 * that may happen before sta_info_insert(). It may only be
214 * called when sta_info_insert() has not been attempted (and
215 * if that fails, the station is freed anyway.)
214 */ 216 */
215static void __sta_info_free(struct ieee80211_local *local, 217void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
216 struct sta_info *sta)
217{ 218{
218 if (sta->rate_ctrl) { 219 if (sta->rate_ctrl) {
219 rate_control_free_sta(sta); 220 rate_control_free_sta(sta);
@@ -598,7 +599,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
598 return 0; 599 return 0;
599 out_free: 600 out_free:
600 BUG_ON(!err); 601 BUG_ON(!err);
601 __sta_info_free(local, sta); 602 sta_info_free(local, sta);
602 return err; 603 return err;
603} 604}
604 605
@@ -905,6 +906,9 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
905 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 906 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
906 RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); 907 RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
907 908
909 while (sta->sta_state > IEEE80211_STA_NONE)
910 sta_info_move_state(sta, sta->sta_state - 1);
911
908 if (sta->uploaded) { 912 if (sta->uploaded) {
909 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 913 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
910 sdata = container_of(sdata->bss, 914 sdata = container_of(sdata->bss,
@@ -974,7 +978,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
974 kfree_rcu(tid_tx, rcu_head); 978 kfree_rcu(tid_tx, rcu_head);
975 } 979 }
976 980
977 __sta_info_free(local, sta); 981 sta_info_free(local, sta);
978 982
979 return 0; 983 return 0;
980} 984}
@@ -1538,3 +1542,52 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
1538 sta_info_recalc_tim(sta); 1542 sta_info_recalc_tim(sta);
1539} 1543}
1540EXPORT_SYMBOL(ieee80211_sta_set_buffered); 1544EXPORT_SYMBOL(ieee80211_sta_set_buffered);
1545
1546int sta_info_move_state_checked(struct sta_info *sta,
1547 enum ieee80211_sta_state new_state)
1548{
1549 /* might_sleep(); -- for driver notify later, fix IBSS first */
1550
1551 if (sta->sta_state == new_state)
1552 return 0;
1553
1554 switch (new_state) {
1555 case IEEE80211_STA_NONE:
1556 if (sta->sta_state == IEEE80211_STA_AUTH)
1557 clear_bit(WLAN_STA_AUTH, &sta->_flags);
1558 else
1559 return -EINVAL;
1560 break;
1561 case IEEE80211_STA_AUTH:
1562 if (sta->sta_state == IEEE80211_STA_NONE)
1563 set_bit(WLAN_STA_AUTH, &sta->_flags);
1564 else if (sta->sta_state == IEEE80211_STA_ASSOC)
1565 clear_bit(WLAN_STA_ASSOC, &sta->_flags);
1566 else
1567 return -EINVAL;
1568 break;
1569 case IEEE80211_STA_ASSOC:
1570 if (sta->sta_state == IEEE80211_STA_AUTH)
1571 set_bit(WLAN_STA_ASSOC, &sta->_flags);
1572 else if (sta->sta_state == IEEE80211_STA_AUTHORIZED)
1573 clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
1574 else
1575 return -EINVAL;
1576 break;
1577 case IEEE80211_STA_AUTHORIZED:
1578 if (sta->sta_state == IEEE80211_STA_ASSOC)
1579 set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
1580 else
1581 return -EINVAL;
1582 break;
1583 default:
1584 WARN(1, "invalid state %d", new_state);
1585 return -EINVAL;
1586 }
1587
1588 printk(KERN_DEBUG "%s: moving STA %pM to state %d\n",
1589 sta->sdata->name, sta->sta.addr, new_state);
1590 sta->sta_state = new_state;
1591
1592 return 0;
1593}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 1a14fab4bc9a..63f4d316a954 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -73,6 +73,14 @@ enum ieee80211_sta_info_flags {
73 WLAN_STA_4ADDR_EVENT, 73 WLAN_STA_4ADDR_EVENT,
74}; 74};
75 75
76enum ieee80211_sta_state {
77 /* NOTE: These need to be ordered correctly! */
78 IEEE80211_STA_NONE,
79 IEEE80211_STA_AUTH,
80 IEEE80211_STA_ASSOC,
81 IEEE80211_STA_AUTHORIZED,
82};
83
76#define STA_TID_NUM 16 84#define STA_TID_NUM 16
77#define ADDBA_RESP_INTERVAL HZ 85#define ADDBA_RESP_INTERVAL HZ
78#define HT_AGG_MAX_RETRIES 0x3 86#define HT_AGG_MAX_RETRIES 0x3
@@ -262,6 +270,7 @@ struct sta_ampdu_mlme {
262 * @dummy: indicate a dummy station created for receiving 270 * @dummy: indicate a dummy station created for receiving
263 * EAP frames before association 271 * EAP frames before association
264 * @sta: station information we share with the driver 272 * @sta: station information we share with the driver
273 * @sta_state: duplicates information about station state (for debug)
265 */ 274 */
266struct sta_info { 275struct sta_info {
267 /* General information, mostly static */ 276 /* General information, mostly static */
@@ -283,6 +292,8 @@ struct sta_info {
283 292
284 bool uploaded; 293 bool uploaded;
285 294
295 enum ieee80211_sta_state sta_state;
296
286 /* use the accessors defined below */ 297 /* use the accessors defined below */
287 unsigned long _flags; 298 unsigned long _flags;
288 299
@@ -371,12 +382,18 @@ static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta)
371static inline void set_sta_flag(struct sta_info *sta, 382static inline void set_sta_flag(struct sta_info *sta,
372 enum ieee80211_sta_info_flags flag) 383 enum ieee80211_sta_info_flags flag)
373{ 384{
385 WARN_ON(flag == WLAN_STA_AUTH ||
386 flag == WLAN_STA_ASSOC ||
387 flag == WLAN_STA_AUTHORIZED);
374 set_bit(flag, &sta->_flags); 388 set_bit(flag, &sta->_flags);
375} 389}
376 390
377static inline void clear_sta_flag(struct sta_info *sta, 391static inline void clear_sta_flag(struct sta_info *sta,
378 enum ieee80211_sta_info_flags flag) 392 enum ieee80211_sta_info_flags flag)
379{ 393{
394 WARN_ON(flag == WLAN_STA_AUTH ||
395 flag == WLAN_STA_ASSOC ||
396 flag == WLAN_STA_AUTHORIZED);
380 clear_bit(flag, &sta->_flags); 397 clear_bit(flag, &sta->_flags);
381} 398}
382 399
@@ -389,15 +406,32 @@ static inline int test_sta_flag(struct sta_info *sta,
389static inline int test_and_clear_sta_flag(struct sta_info *sta, 406static inline int test_and_clear_sta_flag(struct sta_info *sta,
390 enum ieee80211_sta_info_flags flag) 407 enum ieee80211_sta_info_flags flag)
391{ 408{
409 WARN_ON(flag == WLAN_STA_AUTH ||
410 flag == WLAN_STA_ASSOC ||
411 flag == WLAN_STA_AUTHORIZED);
392 return test_and_clear_bit(flag, &sta->_flags); 412 return test_and_clear_bit(flag, &sta->_flags);
393} 413}
394 414
395static inline int test_and_set_sta_flag(struct sta_info *sta, 415static inline int test_and_set_sta_flag(struct sta_info *sta,
396 enum ieee80211_sta_info_flags flag) 416 enum ieee80211_sta_info_flags flag)
397{ 417{
418 WARN_ON(flag == WLAN_STA_AUTH ||
419 flag == WLAN_STA_ASSOC ||
420 flag == WLAN_STA_AUTHORIZED);
398 return test_and_set_bit(flag, &sta->_flags); 421 return test_and_set_bit(flag, &sta->_flags);
399} 422}
400 423
424int sta_info_move_state_checked(struct sta_info *sta,
425 enum ieee80211_sta_state new_state);
426
427static inline void sta_info_move_state(struct sta_info *sta,
428 enum ieee80211_sta_state new_state)
429{
430 int ret = sta_info_move_state_checked(sta, new_state);
431 WARN_ON_ONCE(ret);
432}
433
434
401void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, 435void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
402 struct tid_ampdu_tx *tid_tx); 436 struct tid_ampdu_tx *tid_tx);
403 437
@@ -489,6 +523,9 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
489 */ 523 */
490struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, 524struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
491 u8 *addr, gfp_t gfp); 525 u8 *addr, gfp_t gfp);
526
527void sta_info_free(struct ieee80211_local *local, struct sta_info *sta);
528
492/* 529/*
493 * Insert STA info into hash table/list, returns zero or a 530 * Insert STA info into hash table/list, returns zero or a
494 * -EEXIST if (if the same MAC address is already present). 531 * -EEXIST if (if the same MAC address is already present).
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e74652d38245..50c4be9a6404 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -295,7 +295,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
295 295
296 if (likely(tx->flags & IEEE80211_TX_UNICAST)) { 296 if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
297 if (unlikely(!assoc && 297 if (unlikely(!assoc &&
298 tx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
299 ieee80211_is_data(hdr->frame_control))) { 298 ieee80211_is_data(hdr->frame_control))) {
300#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 299#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
301 printk(KERN_DEBUG "%s: dropped data frame to not " 300 printk(KERN_DEBUG "%s: dropped data frame to not "