aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
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 /net/mac80211/sta_info.c
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>
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r--net/mac80211/sta_info.c65
1 files changed, 59 insertions, 6 deletions
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}