diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 110 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 4 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.h | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 78 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 13 | ||||
-rw-r--r-- | net/mac80211/ieee80211_iface.c | 11 | ||||
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 42 | ||||
-rw-r--r-- | net/mac80211/ieee80211_rate.c | 8 | ||||
-rw-r--r-- | net/mac80211/ieee80211_rate.h | 1 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 123 | ||||
-rw-r--r-- | net/mac80211/key.c | 8 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 5 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 16 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 6 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 30 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 101 | ||||
-rw-r--r-- | net/mac80211/rc80211_pid_algo.c | 25 | ||||
-rw-r--r-- | net/mac80211/rc80211_simple.c | 18 | ||||
-rw-r--r-- | net/mac80211/rx.c | 24 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 387 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 61 | ||||
-rw-r--r-- | net/mac80211/tx.c | 48 | ||||
-rw-r--r-- | net/mac80211/wme.c | 8 |
23 files changed, 668 insertions, 461 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6ac49231efa9..e9ba6fcc0e45 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -136,7 +136,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
136 | struct ieee80211_sub_if_data *sdata; | 136 | struct ieee80211_sub_if_data *sdata; |
137 | struct sta_info *sta = NULL; | 137 | struct sta_info *sta = NULL; |
138 | enum ieee80211_key_alg alg; | 138 | enum ieee80211_key_alg alg; |
139 | int ret; | ||
140 | struct ieee80211_key *key; | 139 | struct ieee80211_key *key; |
141 | 140 | ||
142 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 141 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -170,12 +169,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
170 | 169 | ||
171 | ieee80211_key_link(key, sdata, sta); | 170 | ieee80211_key_link(key, sdata, sta); |
172 | 171 | ||
173 | ret = 0; | 172 | return 0; |
174 | |||
175 | if (sta) | ||
176 | sta_info_put(sta); | ||
177 | |||
178 | return ret; | ||
179 | } | 173 | } |
180 | 174 | ||
181 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 175 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
@@ -184,7 +178,6 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
184 | struct ieee80211_sub_if_data *sdata; | 178 | struct ieee80211_sub_if_data *sdata; |
185 | struct sta_info *sta; | 179 | struct sta_info *sta; |
186 | int ret; | 180 | int ret; |
187 | struct ieee80211_key *key; | ||
188 | 181 | ||
189 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 182 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
190 | 183 | ||
@@ -195,21 +188,18 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
195 | 188 | ||
196 | ret = 0; | 189 | ret = 0; |
197 | if (sta->key) { | 190 | if (sta->key) { |
198 | key = sta->key; | 191 | ieee80211_key_free(sta->key); |
199 | ieee80211_key_free(key); | ||
200 | WARN_ON(sta->key); | 192 | WARN_ON(sta->key); |
201 | } else | 193 | } else |
202 | ret = -ENOENT; | 194 | ret = -ENOENT; |
203 | 195 | ||
204 | sta_info_put(sta); | ||
205 | return ret; | 196 | return ret; |
206 | } | 197 | } |
207 | 198 | ||
208 | if (!sdata->keys[key_idx]) | 199 | if (!sdata->keys[key_idx]) |
209 | return -ENOENT; | 200 | return -ENOENT; |
210 | 201 | ||
211 | key = sdata->keys[key_idx]; | 202 | ieee80211_key_free(sdata->keys[key_idx]); |
212 | ieee80211_key_free(key); | ||
213 | WARN_ON(sdata->keys[key_idx]); | 203 | WARN_ON(sdata->keys[key_idx]); |
214 | 204 | ||
215 | return 0; | 205 | return 0; |
@@ -292,8 +282,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
292 | err = 0; | 282 | err = 0; |
293 | 283 | ||
294 | out: | 284 | out: |
295 | if (sta) | ||
296 | sta_info_put(sta); | ||
297 | return err; | 285 | return err; |
298 | } | 286 | } |
299 | 287 | ||
@@ -311,7 +299,7 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, | |||
311 | 299 | ||
312 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 300 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
313 | { | 301 | { |
314 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 302 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
315 | 303 | ||
316 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 304 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
317 | STATION_INFO_RX_BYTES | | 305 | STATION_INFO_RX_BYTES | |
@@ -340,16 +328,20 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | |||
340 | { | 328 | { |
341 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 329 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
342 | struct sta_info *sta; | 330 | struct sta_info *sta; |
331 | int ret = -ENOENT; | ||
332 | |||
333 | rcu_read_lock(); | ||
343 | 334 | ||
344 | sta = sta_info_get_by_idx(local, idx, dev); | 335 | sta = sta_info_get_by_idx(local, idx, dev); |
345 | if (!sta) | 336 | if (sta) { |
346 | return -ENOENT; | 337 | ret = 0; |
338 | memcpy(mac, sta->addr, ETH_ALEN); | ||
339 | sta_set_sinfo(sta, sinfo); | ||
340 | } | ||
347 | 341 | ||
348 | memcpy(mac, sta->addr, ETH_ALEN); | 342 | rcu_read_unlock(); |
349 | sta_set_sinfo(sta, sinfo); | ||
350 | sta_info_put(sta); | ||
351 | 343 | ||
352 | return 0; | 344 | return ret; |
353 | } | 345 | } |
354 | 346 | ||
355 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 347 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
@@ -357,16 +349,21 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
357 | { | 349 | { |
358 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 350 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
359 | struct sta_info *sta; | 351 | struct sta_info *sta; |
352 | int ret = -ENOENT; | ||
360 | 353 | ||
361 | sta = sta_info_get(local, mac); | 354 | rcu_read_lock(); |
362 | if (!sta) | ||
363 | return -ENOENT; | ||
364 | 355 | ||
365 | /* XXX: verify sta->dev == dev */ | 356 | /* XXX: verify sta->dev == dev */ |
366 | sta_set_sinfo(sta, sinfo); | ||
367 | sta_info_put(sta); | ||
368 | 357 | ||
369 | return 0; | 358 | sta = sta_info_get(local, mac); |
359 | if (sta) { | ||
360 | ret = 0; | ||
361 | sta_set_sinfo(sta, sinfo); | ||
362 | } | ||
363 | |||
364 | rcu_read_unlock(); | ||
365 | |||
366 | return ret; | ||
370 | } | 367 | } |
371 | 368 | ||
372 | /* | 369 | /* |
@@ -559,8 +556,8 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) | |||
559 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ | 556 | msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ |
560 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ | 557 | msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ |
561 | 558 | ||
562 | skb->dev = sta->dev; | 559 | skb->dev = sta->sdata->dev; |
563 | skb->protocol = eth_type_trans(skb, sta->dev); | 560 | skb->protocol = eth_type_trans(skb, sta->sdata->dev); |
564 | memset(skb->cb, 0, sizeof(skb->cb)); | 561 | memset(skb->cb, 0, sizeof(skb->cb)); |
565 | netif_rx(skb); | 562 | netif_rx(skb); |
566 | } | 563 | } |
@@ -572,7 +569,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
572 | u32 rates; | 569 | u32 rates; |
573 | int i, j; | 570 | int i, j; |
574 | struct ieee80211_supported_band *sband; | 571 | struct ieee80211_supported_band *sband; |
575 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 572 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
576 | 573 | ||
577 | if (params->station_flags & STATION_FLAG_CHANGED) { | 574 | if (params->station_flags & STATION_FLAG_CHANGED) { |
578 | sta->flags &= ~WLAN_STA_AUTHORIZED; | 575 | sta->flags &= ~WLAN_STA_AUTHORIZED; |
@@ -644,14 +641,13 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
644 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 641 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
645 | 642 | ||
646 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 643 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
647 | sta = mesh_plink_add(mac, DEFAULT_RATES, dev); | 644 | sta = mesh_plink_add(mac, DEFAULT_RATES, sdata); |
648 | else | 645 | else |
649 | sta = sta_info_add(local, dev, mac, GFP_KERNEL); | 646 | sta = sta_info_add(sdata, mac); |
650 | 647 | ||
651 | if (IS_ERR(sta)) | 648 | if (IS_ERR(sta)) |
652 | return PTR_ERR(sta); | 649 | return PTR_ERR(sta); |
653 | 650 | ||
654 | sta->dev = sdata->dev; | ||
655 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || | 651 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || |
656 | sdata->vif.type == IEEE80211_IF_TYPE_AP) | 652 | sdata->vif.type == IEEE80211_IF_TYPE_AP) |
657 | ieee80211_send_layer2_update(sta); | 653 | ieee80211_send_layer2_update(sta); |
@@ -662,15 +658,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
662 | 658 | ||
663 | rate_control_rate_init(sta, local); | 659 | rate_control_rate_init(sta, local); |
664 | 660 | ||
665 | sta_info_put(sta); | ||
666 | |||
667 | return 0; | 661 | return 0; |
668 | } | 662 | } |
669 | 663 | ||
670 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 664 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
671 | u8 *mac) | 665 | u8 *mac) |
672 | { | 666 | { |
673 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 667 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
668 | struct ieee80211_local *local = sdata->local; | ||
674 | struct sta_info *sta; | 669 | struct sta_info *sta; |
675 | 670 | ||
676 | if (mac) { | 671 | if (mac) { |
@@ -679,10 +674,14 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
679 | if (!sta) | 674 | if (!sta) |
680 | return -ENOENT; | 675 | return -ENOENT; |
681 | 676 | ||
682 | sta_info_free(sta); | 677 | sta_info_unlink(&sta); |
683 | sta_info_put(sta); | 678 | |
679 | if (sta) { | ||
680 | synchronize_rcu(); | ||
681 | sta_info_destroy(sta); | ||
682 | } | ||
684 | } else | 683 | } else |
685 | sta_info_flush(local, dev); | 684 | sta_info_flush(local, sdata); |
686 | 685 | ||
687 | return 0; | 686 | return 0; |
688 | } | 687 | } |
@@ -701,21 +700,19 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
701 | if (!sta) | 700 | if (!sta) |
702 | return -ENOENT; | 701 | return -ENOENT; |
703 | 702 | ||
704 | if (params->vlan && params->vlan != sta->dev) { | 703 | if (params->vlan && params->vlan != sta->sdata->dev) { |
705 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 704 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
706 | 705 | ||
707 | if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || | 706 | if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || |
708 | vlansdata->vif.type != IEEE80211_IF_TYPE_AP) | 707 | vlansdata->vif.type != IEEE80211_IF_TYPE_AP) |
709 | return -EINVAL; | 708 | return -EINVAL; |
710 | 709 | ||
711 | sta->dev = params->vlan; | 710 | sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
712 | ieee80211_send_layer2_update(sta); | 711 | ieee80211_send_layer2_update(sta); |
713 | } | 712 | } |
714 | 713 | ||
715 | sta_apply_parameters(local, sta, params); | 714 | sta_apply_parameters(local, sta, params); |
716 | 715 | ||
717 | sta_info_put(sta); | ||
718 | |||
719 | return 0; | 716 | return 0; |
720 | } | 717 | } |
721 | 718 | ||
@@ -735,23 +732,26 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
735 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | 732 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) |
736 | return -ENOTSUPP; | 733 | return -ENOTSUPP; |
737 | 734 | ||
735 | rcu_read_lock(); | ||
738 | sta = sta_info_get(local, next_hop); | 736 | sta = sta_info_get(local, next_hop); |
739 | if (!sta) | 737 | if (!sta) { |
738 | rcu_read_unlock(); | ||
740 | return -ENOENT; | 739 | return -ENOENT; |
740 | } | ||
741 | 741 | ||
742 | err = mesh_path_add(dst, dev); | 742 | err = mesh_path_add(dst, dev); |
743 | if (err) | 743 | if (err) { |
744 | rcu_read_unlock(); | ||
744 | return err; | 745 | return err; |
746 | } | ||
745 | 747 | ||
746 | rcu_read_lock(); | ||
747 | mpath = mesh_path_lookup(dst, dev); | 748 | mpath = mesh_path_lookup(dst, dev); |
748 | if (!mpath) { | 749 | if (!mpath) { |
749 | rcu_read_unlock(); | 750 | rcu_read_unlock(); |
750 | sta_info_put(sta); | ||
751 | return -ENXIO; | 751 | return -ENXIO; |
752 | } | 752 | } |
753 | mesh_path_fix_nexthop(mpath, sta); | 753 | mesh_path_fix_nexthop(mpath, sta); |
754 | sta_info_put(sta); | 754 | |
755 | rcu_read_unlock(); | 755 | rcu_read_unlock(); |
756 | return 0; | 756 | return 0; |
757 | } | 757 | } |
@@ -760,7 +760,7 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
760 | u8 *dst) | 760 | u8 *dst) |
761 | { | 761 | { |
762 | if (dst) | 762 | if (dst) |
763 | return mesh_path_del(dst, dev); | 763 | return mesh_path_del(dst, dev, false); |
764 | 764 | ||
765 | mesh_path_flush(dev); | 765 | mesh_path_flush(dev); |
766 | return 0; | 766 | return 0; |
@@ -781,20 +781,22 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
781 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) | 781 | if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) |
782 | return -ENOTSUPP; | 782 | return -ENOTSUPP; |
783 | 783 | ||
784 | rcu_read_lock(); | ||
785 | |||
784 | sta = sta_info_get(local, next_hop); | 786 | sta = sta_info_get(local, next_hop); |
785 | if (!sta) | 787 | if (!sta) { |
788 | rcu_read_unlock(); | ||
786 | return -ENOENT; | 789 | return -ENOENT; |
790 | } | ||
787 | 791 | ||
788 | rcu_read_lock(); | ||
789 | mpath = mesh_path_lookup(dst, dev); | 792 | mpath = mesh_path_lookup(dst, dev); |
790 | if (!mpath) { | 793 | if (!mpath) { |
791 | rcu_read_unlock(); | 794 | rcu_read_unlock(); |
792 | sta_info_put(sta); | ||
793 | return -ENOENT; | 795 | return -ENOENT; |
794 | } | 796 | } |
795 | 797 | ||
796 | mesh_path_fix_nexthop(mpath, sta); | 798 | mesh_path_fix_nexthop(mpath, sta); |
797 | sta_info_put(sta); | 799 | |
798 | rcu_read_unlock(); | 800 | rcu_read_unlock(); |
799 | return 0; | 801 | return 0; |
800 | } | 802 | } |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index ed7c9f3b4602..73cfb4da464d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -51,7 +51,7 @@ static const struct file_operations sta_ ##name## _ops = { \ | |||
51 | STA_OPS(name) | 51 | STA_OPS(name) |
52 | 52 | ||
53 | STA_FILE(aid, aid, D); | 53 | STA_FILE(aid, aid, D); |
54 | STA_FILE(dev, dev->name, S); | 54 | STA_FILE(dev, sdata->dev->name, S); |
55 | STA_FILE(rx_packets, rx_packets, LU); | 55 | STA_FILE(rx_packets, rx_packets, LU); |
56 | STA_FILE(tx_packets, tx_packets, LU); | 56 | STA_FILE(tx_packets, tx_packets, LU); |
57 | STA_FILE(rx_bytes, rx_bytes, LU); | 57 | STA_FILE(rx_bytes, rx_bytes, LU); |
@@ -200,7 +200,7 @@ static ssize_t sta_agg_status_write(struct file *file, | |||
200 | const char __user *user_buf, size_t count, loff_t *ppos) | 200 | const char __user *user_buf, size_t count, loff_t *ppos) |
201 | { | 201 | { |
202 | struct sta_info *sta = file->private_data; | 202 | struct sta_info *sta = file->private_data; |
203 | struct net_device *dev = sta->dev; | 203 | struct net_device *dev = sta->sdata->dev; |
204 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 204 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
205 | struct ieee80211_hw *hw = &local->hw; | 205 | struct ieee80211_hw *hw = &local->hw; |
206 | u8 *da = sta->addr; | 206 | u8 *da = sta->addr; |
diff --git a/net/mac80211/debugfs_sta.h b/net/mac80211/debugfs_sta.h index 574a1cd54b96..8b608903259f 100644 --- a/net/mac80211/debugfs_sta.h +++ b/net/mac80211/debugfs_sta.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef __MAC80211_DEBUGFS_STA_H | 1 | #ifndef __MAC80211_DEBUGFS_STA_H |
2 | #define __MAC80211_DEBUGFS_STA_H | 2 | #define __MAC80211_DEBUGFS_STA_H |
3 | 3 | ||
4 | #include "sta_info.h" | ||
5 | |||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | 6 | #ifdef CONFIG_MAC80211_DEBUGFS |
5 | void ieee80211_sta_debugfs_add(struct sta_info *sta); | 7 | void ieee80211_sta_debugfs_add(struct sta_info *sta); |
6 | void ieee80211_sta_debugfs_remove(struct sta_info *sta); | 8 | void ieee80211_sta_debugfs_remove(struct sta_info *sta); |
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 |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d3b5cc57af40..8e440c5706dd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -574,6 +574,7 @@ struct ieee80211_local { | |||
574 | unsigned int filter_flags; /* FIF_* */ | 574 | unsigned int filter_flags; /* FIF_* */ |
575 | struct iw_statistics wstats; | 575 | struct iw_statistics wstats; |
576 | u8 wstats_flags; | 576 | u8 wstats_flags; |
577 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ | ||
577 | int tx_headroom; /* required headroom for hardware/radiotap */ | 578 | int tx_headroom; /* required headroom for hardware/radiotap */ |
578 | 579 | ||
579 | enum { | 580 | enum { |
@@ -591,9 +592,15 @@ struct ieee80211_local { | |||
591 | struct sk_buff_head skb_queue; | 592 | struct sk_buff_head skb_queue; |
592 | struct sk_buff_head skb_queue_unreliable; | 593 | struct sk_buff_head skb_queue_unreliable; |
593 | 594 | ||
594 | /* Station data structures */ | 595 | /* Station data */ |
595 | rwlock_t sta_lock; /* protects STA data structures */ | 596 | /* |
596 | int num_sta; /* number of stations in sta_list */ | 597 | * The lock only protects the list, hash, timer and counter |
598 | * against manipulation, reads are done in RCU. Additionally, | ||
599 | * the lock protects each BSS's TIM bitmap and a few items | ||
600 | * in a STA info structure. | ||
601 | */ | ||
602 | spinlock_t sta_lock; | ||
603 | unsigned long num_sta; | ||
597 | struct list_head sta_list; | 604 | struct list_head sta_list; |
598 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 605 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
599 | struct timer_list sta_cleanup; | 606 | struct timer_list sta_cleanup; |
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index b0f17a2b1a42..98b22736e883 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c | |||
@@ -240,16 +240,21 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
240 | break; | 240 | break; |
241 | } | 241 | } |
242 | case IEEE80211_IF_TYPE_WDS: | 242 | case IEEE80211_IF_TYPE_WDS: |
243 | rcu_read_lock(); | ||
243 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | 244 | sta = sta_info_get(local, sdata->u.wds.remote_addr); |
244 | if (sta) { | 245 | if (sta) { |
245 | sta_info_free(sta); | 246 | sta_info_unlink(&sta); |
246 | sta_info_put(sta); | ||
247 | } else { | 247 | } else { |
248 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 248 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
249 | printk(KERN_DEBUG "%s: Someone had deleted my STA " | 249 | printk(KERN_DEBUG "%s: Someone had deleted my STA " |
250 | "entry for the WDS link\n", dev->name); | 250 | "entry for the WDS link\n", dev->name); |
251 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 251 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
252 | } | 252 | } |
253 | rcu_read_unlock(); | ||
254 | if (sta) { | ||
255 | synchronize_rcu(); | ||
256 | sta_info_destroy(sta); | ||
257 | } | ||
253 | break; | 258 | break; |
254 | case IEEE80211_IF_TYPE_MESH_POINT: | 259 | case IEEE80211_IF_TYPE_MESH_POINT: |
255 | case IEEE80211_IF_TYPE_STA: | 260 | case IEEE80211_IF_TYPE_STA: |
@@ -275,7 +280,7 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
275 | } | 280 | } |
276 | 281 | ||
277 | /* remove all STAs that are bound to this virtual interface */ | 282 | /* remove all STAs that are bound to this virtual interface */ |
278 | sta_info_flush(local, dev); | 283 | sta_info_flush(local, sdata); |
279 | 284 | ||
280 | memset(&sdata->u, 0, sizeof(sdata->u)); | 285 | memset(&sdata->u, 0, sizeof(sdata->u)); |
281 | ieee80211_if_sdata_init(sdata); | 286 | ieee80211_if_sdata_init(sdata); |
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 38e2d83e15f4..5147152b9268 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -33,8 +33,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
33 | size_t key_len) | 33 | size_t key_len) |
34 | { | 34 | { |
35 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 35 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
36 | int ret; | 36 | struct sta_info *sta; |
37 | struct sta_info *sta = NULL; | ||
38 | struct ieee80211_key *key; | 37 | struct ieee80211_key *key; |
39 | struct ieee80211_sub_if_data *sdata; | 38 | struct ieee80211_sub_if_data *sdata; |
40 | 39 | ||
@@ -51,24 +50,23 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
51 | key = sdata->keys[idx]; | 50 | key = sdata->keys[idx]; |
52 | } else { | 51 | } else { |
53 | sta = sta_info_get(local, sta_addr); | 52 | sta = sta_info_get(local, sta_addr); |
54 | if (!sta) { | 53 | if (!sta) |
55 | ret = -ENOENT; | 54 | return -ENOENT; |
56 | key = NULL; | ||
57 | goto err_out; | ||
58 | } | ||
59 | |||
60 | key = sta->key; | 55 | key = sta->key; |
61 | } | 56 | } |
62 | 57 | ||
63 | if (!key) | 58 | if (!key) |
64 | ret = -ENOENT; | 59 | return -ENOENT; |
65 | else | 60 | |
66 | ret = 0; | 61 | ieee80211_key_free(key); |
62 | return 0; | ||
67 | } else { | 63 | } else { |
68 | key = ieee80211_key_alloc(alg, idx, key_len, _key); | 64 | key = ieee80211_key_alloc(alg, idx, key_len, _key); |
69 | if (!key) | 65 | if (!key) |
70 | return -ENOMEM; | 66 | return -ENOMEM; |
71 | 67 | ||
68 | sta = NULL; | ||
69 | |||
72 | if (!is_broadcast_ether_addr(sta_addr)) { | 70 | if (!is_broadcast_ether_addr(sta_addr)) { |
73 | set_tx_key = 0; | 71 | set_tx_key = 0; |
74 | /* | 72 | /* |
@@ -78,14 +76,14 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
78 | * work around this. | 76 | * work around this. |
79 | */ | 77 | */ |
80 | if (idx != 0 && alg != ALG_WEP) { | 78 | if (idx != 0 && alg != ALG_WEP) { |
81 | ret = -EINVAL; | 79 | ieee80211_key_free(key); |
82 | goto err_out; | 80 | return -EINVAL; |
83 | } | 81 | } |
84 | 82 | ||
85 | sta = sta_info_get(local, sta_addr); | 83 | sta = sta_info_get(local, sta_addr); |
86 | if (!sta) { | 84 | if (!sta) { |
87 | ret = -ENOENT; | 85 | ieee80211_key_free(key); |
88 | goto err_out; | 86 | return -ENOENT; |
89 | } | 87 | } |
90 | } | 88 | } |
91 | 89 | ||
@@ -93,18 +91,9 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
93 | 91 | ||
94 | if (set_tx_key || (!sta && !sdata->default_key && key)) | 92 | if (set_tx_key || (!sta && !sdata->default_key && key)) |
95 | ieee80211_set_default_key(sdata, idx); | 93 | ieee80211_set_default_key(sdata, idx); |
96 | |||
97 | /* don't free key later */ | ||
98 | key = NULL; | ||
99 | |||
100 | ret = 0; | ||
101 | } | 94 | } |
102 | 95 | ||
103 | err_out: | 96 | return 0; |
104 | if (sta) | ||
105 | sta_info_put(sta); | ||
106 | ieee80211_key_free(key); | ||
107 | return ret; | ||
108 | } | 97 | } |
109 | 98 | ||
110 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, | 99 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, |
@@ -625,7 +614,7 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, | |||
625 | else | 614 | else |
626 | rate->value = 0; | 615 | rate->value = 0; |
627 | rate->value *= 100000; | 616 | rate->value *= 100000; |
628 | sta_info_put(sta); | 617 | |
629 | return 0; | 618 | return 0; |
630 | } | 619 | } |
631 | 620 | ||
@@ -1000,7 +989,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev | |||
1000 | wstats->qual.qual = sta->last_signal; | 989 | wstats->qual.qual = sta->last_signal; |
1001 | wstats->qual.noise = sta->last_noise; | 990 | wstats->qual.noise = sta->last_noise; |
1002 | wstats->qual.updated = local->wstats_flags; | 991 | wstats->qual.updated = local->wstats_flags; |
1003 | sta_info_put(sta); | ||
1004 | } | 992 | } |
1005 | return wstats; | 993 | return wstats; |
1006 | } | 994 | } |
diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index ebe29b716b27..4de06f128d90 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c | |||
@@ -170,9 +170,12 @@ void rate_control_get_rate(struct net_device *dev, | |||
170 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 170 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
171 | struct rate_control_ref *ref = local->rate_ctrl; | 171 | struct rate_control_ref *ref = local->rate_ctrl; |
172 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 172 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
173 | struct sta_info *sta = sta_info_get(local, hdr->addr1); | 173 | struct sta_info *sta; |
174 | int i; | 174 | int i; |
175 | 175 | ||
176 | rcu_read_lock(); | ||
177 | sta = sta_info_get(local, hdr->addr1); | ||
178 | |||
176 | memset(sel, 0, sizeof(struct rate_selection)); | 179 | memset(sel, 0, sizeof(struct rate_selection)); |
177 | 180 | ||
178 | ref->ops->get_rate(ref->priv, dev, sband, skb, sel); | 181 | ref->ops->get_rate(ref->priv, dev, sband, skb, sel); |
@@ -190,8 +193,7 @@ void rate_control_get_rate(struct net_device *dev, | |||
190 | } | 193 | } |
191 | } | 194 | } |
192 | 195 | ||
193 | if (sta) | 196 | rcu_read_unlock(); |
194 | sta_info_put(sta); | ||
195 | } | 197 | } |
196 | 198 | ||
197 | struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) | 199 | struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) |
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index 5f9a2ca49a57..bfd0a1982e4a 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/netdevice.h> | 14 | #include <linux/netdevice.h> |
15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/kref.h> | ||
17 | #include <net/mac80211.h> | 18 | #include <net/mac80211.h> |
18 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
19 | #include "sta_info.h" | 20 | #include "sta_info.h" |
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 9f933aeca719..a3e96eb59eb0 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/wireless.h> | 24 | #include <linux/wireless.h> |
25 | #include <linux/random.h> | 25 | #include <linux/random.h> |
26 | #include <linux/etherdevice.h> | 26 | #include <linux/etherdevice.h> |
27 | #include <linux/rtnetlink.h> | ||
27 | #include <net/iw_handler.h> | 28 | #include <net/iw_handler.h> |
28 | #include <asm/types.h> | 29 | #include <asm/types.h> |
29 | 30 | ||
@@ -845,6 +846,8 @@ static void ieee80211_associated(struct net_device *dev, | |||
845 | 846 | ||
846 | ifsta->state = IEEE80211_ASSOCIATED; | 847 | ifsta->state = IEEE80211_ASSOCIATED; |
847 | 848 | ||
849 | rcu_read_lock(); | ||
850 | |||
848 | sta = sta_info_get(local, ifsta->bssid); | 851 | sta = sta_info_get(local, ifsta->bssid); |
849 | if (!sta) { | 852 | if (!sta) { |
850 | printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", | 853 | printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", |
@@ -860,7 +863,7 @@ static void ieee80211_associated(struct net_device *dev, | |||
860 | "range\n", | 863 | "range\n", |
861 | dev->name, print_mac(mac, ifsta->bssid)); | 864 | dev->name, print_mac(mac, ifsta->bssid)); |
862 | disassoc = 1; | 865 | disassoc = 1; |
863 | sta_info_free(sta); | 866 | sta_info_unlink(&sta); |
864 | } else | 867 | } else |
865 | ieee80211_send_probe_req(dev, ifsta->bssid, | 868 | ieee80211_send_probe_req(dev, ifsta->bssid, |
866 | local->scan_ssid, | 869 | local->scan_ssid, |
@@ -876,8 +879,17 @@ static void ieee80211_associated(struct net_device *dev, | |||
876 | ifsta->ssid_len); | 879 | ifsta->ssid_len); |
877 | } | 880 | } |
878 | } | 881 | } |
879 | sta_info_put(sta); | ||
880 | } | 882 | } |
883 | |||
884 | rcu_read_unlock(); | ||
885 | |||
886 | if (disassoc && sta) { | ||
887 | synchronize_rcu(); | ||
888 | rtnl_lock(); | ||
889 | sta_info_destroy(sta); | ||
890 | rtnl_unlock(); | ||
891 | } | ||
892 | |||
881 | if (disassoc) { | 893 | if (disassoc) { |
882 | ifsta->state = IEEE80211_DISABLED; | 894 | ifsta->state = IEEE80211_DISABLED; |
883 | ieee80211_set_associated(dev, ifsta, 0); | 895 | ieee80211_set_associated(dev, ifsta, 0); |
@@ -1103,9 +1115,13 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, | |||
1103 | int ret = -EOPNOTSUPP; | 1115 | int ret = -EOPNOTSUPP; |
1104 | DECLARE_MAC_BUF(mac); | 1116 | DECLARE_MAC_BUF(mac); |
1105 | 1117 | ||
1118 | rcu_read_lock(); | ||
1119 | |||
1106 | sta = sta_info_get(local, mgmt->sa); | 1120 | sta = sta_info_get(local, mgmt->sa); |
1107 | if (!sta) | 1121 | if (!sta) { |
1122 | rcu_read_unlock(); | ||
1108 | return; | 1123 | return; |
1124 | } | ||
1109 | 1125 | ||
1110 | /* extract session parameters from addba request frame */ | 1126 | /* extract session parameters from addba request frame */ |
1111 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | 1127 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; |
@@ -1197,9 +1213,9 @@ end: | |||
1197 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); | 1213 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); |
1198 | 1214 | ||
1199 | end_no_lock: | 1215 | end_no_lock: |
1200 | ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token, | 1216 | ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, |
1201 | status, 1, buf_size, timeout); | 1217 | dialog_token, status, 1, buf_size, timeout); |
1202 | sta_info_put(sta); | 1218 | rcu_read_unlock(); |
1203 | } | 1219 | } |
1204 | 1220 | ||
1205 | static void ieee80211_sta_process_addba_resp(struct net_device *dev, | 1221 | static void ieee80211_sta_process_addba_resp(struct net_device *dev, |
@@ -1213,9 +1229,13 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1213 | u16 tid; | 1229 | u16 tid; |
1214 | u8 *state; | 1230 | u8 *state; |
1215 | 1231 | ||
1232 | rcu_read_lock(); | ||
1233 | |||
1216 | sta = sta_info_get(local, mgmt->sa); | 1234 | sta = sta_info_get(local, mgmt->sa); |
1217 | if (!sta) | 1235 | if (!sta) { |
1236 | rcu_read_unlock(); | ||
1218 | return; | 1237 | return; |
1238 | } | ||
1219 | 1239 | ||
1220 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | 1240 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); |
1221 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | 1241 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; |
@@ -1230,7 +1250,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1230 | #ifdef CONFIG_MAC80211_HT_DEBUG | 1250 | #ifdef CONFIG_MAC80211_HT_DEBUG |
1231 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); | 1251 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); |
1232 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 1252 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
1233 | sta_info_put(sta); | 1253 | rcu_read_unlock(); |
1234 | return; | 1254 | return; |
1235 | } | 1255 | } |
1236 | 1256 | ||
@@ -1244,7 +1264,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1244 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 1264 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
1245 | printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" | 1265 | printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" |
1246 | "%d\n", *state); | 1266 | "%d\n", *state); |
1247 | sta_info_put(sta); | 1267 | rcu_read_unlock(); |
1248 | return; | 1268 | return; |
1249 | } | 1269 | } |
1250 | 1270 | ||
@@ -1271,7 +1291,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1271 | ieee80211_stop_tx_ba_session(hw, sta->addr, tid, | 1291 | ieee80211_stop_tx_ba_session(hw, sta->addr, tid, |
1272 | WLAN_BACK_INITIATOR); | 1292 | WLAN_BACK_INITIATOR); |
1273 | } | 1293 | } |
1274 | sta_info_put(sta); | 1294 | rcu_read_unlock(); |
1275 | } | 1295 | } |
1276 | 1296 | ||
1277 | void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, | 1297 | void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, |
@@ -1326,16 +1346,20 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, | |||
1326 | struct sta_info *sta; | 1346 | struct sta_info *sta; |
1327 | int ret, i; | 1347 | int ret, i; |
1328 | 1348 | ||
1349 | rcu_read_lock(); | ||
1350 | |||
1329 | sta = sta_info_get(local, ra); | 1351 | sta = sta_info_get(local, ra); |
1330 | if (!sta) | 1352 | if (!sta) { |
1353 | rcu_read_unlock(); | ||
1331 | return; | 1354 | return; |
1355 | } | ||
1332 | 1356 | ||
1333 | /* check if TID is in operational state */ | 1357 | /* check if TID is in operational state */ |
1334 | spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); | 1358 | spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); |
1335 | if (sta->ampdu_mlme.tid_rx[tid].state | 1359 | if (sta->ampdu_mlme.tid_rx[tid].state |
1336 | != HT_AGG_STATE_OPERATIONAL) { | 1360 | != HT_AGG_STATE_OPERATIONAL) { |
1337 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); | 1361 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); |
1338 | sta_info_put(sta); | 1362 | rcu_read_unlock(); |
1339 | return; | 1363 | return; |
1340 | } | 1364 | } |
1341 | sta->ampdu_mlme.tid_rx[tid].state = | 1365 | sta->ampdu_mlme.tid_rx[tid].state = |
@@ -1374,7 +1398,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, | |||
1374 | kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); | 1398 | kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); |
1375 | 1399 | ||
1376 | sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; | 1400 | sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; |
1377 | sta_info_put(sta); | 1401 | rcu_read_unlock(); |
1378 | } | 1402 | } |
1379 | 1403 | ||
1380 | 1404 | ||
@@ -1387,9 +1411,13 @@ static void ieee80211_sta_process_delba(struct net_device *dev, | |||
1387 | u16 initiator; | 1411 | u16 initiator; |
1388 | DECLARE_MAC_BUF(mac); | 1412 | DECLARE_MAC_BUF(mac); |
1389 | 1413 | ||
1414 | rcu_read_lock(); | ||
1415 | |||
1390 | sta = sta_info_get(local, mgmt->sa); | 1416 | sta = sta_info_get(local, mgmt->sa); |
1391 | if (!sta) | 1417 | if (!sta) { |
1418 | rcu_read_unlock(); | ||
1392 | return; | 1419 | return; |
1420 | } | ||
1393 | 1421 | ||
1394 | params = le16_to_cpu(mgmt->u.action.u.delba.params); | 1422 | params = le16_to_cpu(mgmt->u.action.u.delba.params); |
1395 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; | 1423 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; |
@@ -1414,7 +1442,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev, | |||
1414 | ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, | 1442 | ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, |
1415 | WLAN_BACK_RECIPIENT); | 1443 | WLAN_BACK_RECIPIENT); |
1416 | } | 1444 | } |
1417 | sta_info_put(sta); | 1445 | rcu_read_unlock(); |
1418 | } | 1446 | } |
1419 | 1447 | ||
1420 | /* | 1448 | /* |
@@ -1437,9 +1465,13 @@ void sta_addba_resp_timer_expired(unsigned long data) | |||
1437 | struct sta_info *sta; | 1465 | struct sta_info *sta; |
1438 | u8 *state; | 1466 | u8 *state; |
1439 | 1467 | ||
1468 | rcu_read_lock(); | ||
1469 | |||
1440 | sta = sta_info_get(local, temp_sta->addr); | 1470 | sta = sta_info_get(local, temp_sta->addr); |
1441 | if (!sta) | 1471 | if (!sta) { |
1472 | rcu_read_unlock(); | ||
1442 | return; | 1473 | return; |
1474 | } | ||
1443 | 1475 | ||
1444 | state = &sta->ampdu_mlme.tid_tx[tid].state; | 1476 | state = &sta->ampdu_mlme.tid_tx[tid].state; |
1445 | /* check if the TID waits for addBA response */ | 1477 | /* check if the TID waits for addBA response */ |
@@ -1461,7 +1493,7 @@ void sta_addba_resp_timer_expired(unsigned long data) | |||
1461 | WLAN_BACK_INITIATOR); | 1493 | WLAN_BACK_INITIATOR); |
1462 | 1494 | ||
1463 | timer_expired_exit: | 1495 | timer_expired_exit: |
1464 | sta_info_put(sta); | 1496 | rcu_read_unlock(); |
1465 | } | 1497 | } |
1466 | 1498 | ||
1467 | /* | 1499 | /* |
@@ -1481,8 +1513,8 @@ void sta_rx_agg_session_timer_expired(unsigned long data) | |||
1481 | timer_to_tid[0]); | 1513 | timer_to_tid[0]); |
1482 | 1514 | ||
1483 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | 1515 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); |
1484 | ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid, | 1516 | ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, |
1485 | WLAN_BACK_TIMER, | 1517 | (u16)*ptid, WLAN_BACK_TIMER, |
1486 | WLAN_REASON_QSTA_TIMEOUT); | 1518 | WLAN_REASON_QSTA_TIMEOUT); |
1487 | } | 1519 | } |
1488 | 1520 | ||
@@ -1791,14 +1823,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1791 | if (ifsta->assocresp_ies) | 1823 | if (ifsta->assocresp_ies) |
1792 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); | 1824 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); |
1793 | 1825 | ||
1826 | rcu_read_lock(); | ||
1827 | |||
1794 | /* Add STA entry for the AP */ | 1828 | /* Add STA entry for the AP */ |
1795 | sta = sta_info_get(local, ifsta->bssid); | 1829 | sta = sta_info_get(local, ifsta->bssid); |
1796 | if (!sta) { | 1830 | if (!sta) { |
1797 | struct ieee80211_sta_bss *bss; | 1831 | struct ieee80211_sta_bss *bss; |
1798 | sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); | 1832 | |
1833 | sta = sta_info_add(sdata, ifsta->bssid); | ||
1799 | if (IS_ERR(sta)) { | 1834 | if (IS_ERR(sta)) { |
1800 | printk(KERN_DEBUG "%s: failed to add STA entry for the" | 1835 | printk(KERN_DEBUG "%s: failed to add STA entry for the" |
1801 | " AP (error %ld)\n", dev->name, PTR_ERR(sta)); | 1836 | " AP (error %ld)\n", dev->name, PTR_ERR(sta)); |
1837 | rcu_read_unlock(); | ||
1802 | return; | 1838 | return; |
1803 | } | 1839 | } |
1804 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, | 1840 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, |
@@ -1812,7 +1848,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1812 | } | 1848 | } |
1813 | } | 1849 | } |
1814 | 1850 | ||
1815 | sta->dev = dev; | ||
1816 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | | 1851 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | |
1817 | WLAN_STA_AUTHORIZED; | 1852 | WLAN_STA_AUTHORIZED; |
1818 | 1853 | ||
@@ -1883,7 +1918,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1883 | bss_conf->aid = aid; | 1918 | bss_conf->aid = aid; |
1884 | ieee80211_set_associated(dev, ifsta, 1); | 1919 | ieee80211_set_associated(dev, ifsta, 1); |
1885 | 1920 | ||
1886 | sta_info_put(sta); | 1921 | rcu_read_unlock(); |
1887 | 1922 | ||
1888 | ieee80211_associated(dev, ifsta); | 1923 | ieee80211_associated(dev, ifsta); |
1889 | } | 1924 | } |
@@ -2329,6 +2364,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2329 | mesh_peer_accepts_plinks(&elems, dev)); | 2364 | mesh_peer_accepts_plinks(&elems, dev)); |
2330 | } | 2365 | } |
2331 | 2366 | ||
2367 | rcu_read_lock(); | ||
2368 | |||
2332 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && | 2369 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && |
2333 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && | 2370 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && |
2334 | (sta = sta_info_get(local, mgmt->sa))) { | 2371 | (sta = sta_info_get(local, mgmt->sa))) { |
@@ -2354,9 +2391,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2354 | (unsigned long long) supp_rates, | 2391 | (unsigned long long) supp_rates, |
2355 | (unsigned long long) sta->supp_rates[rx_status->band]); | 2392 | (unsigned long long) sta->supp_rates[rx_status->band]); |
2356 | } | 2393 | } |
2357 | sta_info_put(sta); | ||
2358 | } | 2394 | } |
2359 | 2395 | ||
2396 | rcu_read_unlock(); | ||
2397 | |||
2360 | if (elems.ds_params && elems.ds_params_len == 1) | 2398 | if (elems.ds_params && elems.ds_params_len == 1) |
2361 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); | 2399 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); |
2362 | else | 2400 | else |
@@ -2550,8 +2588,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2550 | "local TSF - IBSS merge with BSSID %s\n", | 2588 | "local TSF - IBSS merge with BSSID %s\n", |
2551 | dev->name, print_mac(mac, mgmt->bssid)); | 2589 | dev->name, print_mac(mac, mgmt->bssid)); |
2552 | ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); | 2590 | ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); |
2591 | rcu_read_lock(); | ||
2553 | ieee80211_ibss_add_sta(dev, NULL, | 2592 | ieee80211_ibss_add_sta(dev, NULL, |
2554 | mgmt->bssid, mgmt->sa); | 2593 | mgmt->bssid, mgmt->sa); |
2594 | rcu_read_unlock(); | ||
2555 | } | 2595 | } |
2556 | } | 2596 | } |
2557 | 2597 | ||
@@ -2893,17 +2933,20 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) | |||
2893 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 2933 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
2894 | int active = 0; | 2934 | int active = 0; |
2895 | struct sta_info *sta; | 2935 | struct sta_info *sta; |
2936 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2896 | 2937 | ||
2897 | read_lock_bh(&local->sta_lock); | 2938 | rcu_read_lock(); |
2898 | list_for_each_entry(sta, &local->sta_list, list) { | 2939 | |
2899 | if (sta->dev == dev && | 2940 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
2941 | if (sta->sdata == sdata && | ||
2900 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | 2942 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, |
2901 | jiffies)) { | 2943 | jiffies)) { |
2902 | active++; | 2944 | active++; |
2903 | break; | 2945 | break; |
2904 | } | 2946 | } |
2905 | } | 2947 | } |
2906 | read_unlock_bh(&local->sta_lock); | 2948 | |
2949 | rcu_read_unlock(); | ||
2907 | 2950 | ||
2908 | return active; | 2951 | return active; |
2909 | } | 2952 | } |
@@ -2915,22 +2958,25 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) | |||
2915 | struct sta_info *sta, *tmp; | 2958 | struct sta_info *sta, *tmp; |
2916 | LIST_HEAD(tmp_list); | 2959 | LIST_HEAD(tmp_list); |
2917 | DECLARE_MAC_BUF(mac); | 2960 | DECLARE_MAC_BUF(mac); |
2961 | unsigned long flags; | ||
2918 | 2962 | ||
2919 | write_lock_bh(&local->sta_lock); | 2963 | spin_lock_irqsave(&local->sta_lock, flags); |
2920 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 2964 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
2921 | if (time_after(jiffies, sta->last_rx + exp_time)) { | 2965 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
2922 | printk(KERN_DEBUG "%s: expiring inactive STA %s\n", | 2966 | printk(KERN_DEBUG "%s: expiring inactive STA %s\n", |
2923 | dev->name, print_mac(mac, sta->addr)); | 2967 | dev->name, print_mac(mac, sta->addr)); |
2924 | __sta_info_get(sta); | 2968 | sta_info_unlink(&sta); |
2925 | sta_info_remove(sta); | 2969 | if (sta) |
2926 | list_add(&sta->list, &tmp_list); | 2970 | list_add(&sta->list, &tmp_list); |
2927 | } | 2971 | } |
2928 | write_unlock_bh(&local->sta_lock); | 2972 | spin_unlock_irqrestore(&local->sta_lock, flags); |
2929 | 2973 | ||
2930 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) { | 2974 | synchronize_rcu(); |
2931 | sta_info_free(sta); | 2975 | |
2932 | sta_info_put(sta); | 2976 | rtnl_lock(); |
2933 | } | 2977 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) |
2978 | sta_info_destroy(sta); | ||
2979 | rtnl_unlock(); | ||
2934 | } | 2980 | } |
2935 | 2981 | ||
2936 | 2982 | ||
@@ -3977,6 +4023,7 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) | |||
3977 | } | 4023 | } |
3978 | 4024 | ||
3979 | 4025 | ||
4026 | /* must be called under RCU read lock */ | ||
3980 | struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | 4027 | struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, |
3981 | struct sk_buff *skb, u8 *bssid, | 4028 | struct sk_buff *skb, u8 *bssid, |
3982 | u8 *addr) | 4029 | u8 *addr) |
@@ -3999,7 +4046,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | |||
3999 | printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", | 4046 | printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", |
4000 | wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); | 4047 | wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); |
4001 | 4048 | ||
4002 | sta = sta_info_add(local, dev, addr, GFP_ATOMIC); | 4049 | sta = sta_info_add(sdata, addr); |
4003 | if (IS_ERR(sta)) | 4050 | if (IS_ERR(sta)) |
4004 | return NULL; | 4051 | return NULL; |
4005 | 4052 | ||
@@ -4010,7 +4057,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | |||
4010 | 4057 | ||
4011 | rate_control_rate_init(sta, local); | 4058 | rate_control_rate_init(sta, local); |
4012 | 4059 | ||
4013 | return sta; /* caller will call sta_info_put() */ | 4060 | return sta; |
4014 | } | 4061 | } |
4015 | 4062 | ||
4016 | 4063 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index eac9c59dbc4d..df0c04cedbe4 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -240,14 +240,17 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
240 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { | 240 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { |
241 | struct sta_info *ap; | 241 | struct sta_info *ap; |
242 | 242 | ||
243 | rcu_read_lock(); | ||
244 | |||
243 | /* same here, the AP could be using QoS */ | 245 | /* same here, the AP could be using QoS */ |
244 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); | 246 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); |
245 | if (ap) { | 247 | if (ap) { |
246 | if (ap->flags & WLAN_STA_WME) | 248 | if (ap->flags & WLAN_STA_WME) |
247 | key->conf.flags |= | 249 | key->conf.flags |= |
248 | IEEE80211_KEY_FLAG_WMM_STA; | 250 | IEEE80211_KEY_FLAG_WMM_STA; |
249 | sta_info_put(ap); | ||
250 | } | 251 | } |
252 | |||
253 | rcu_read_unlock(); | ||
251 | } | 254 | } |
252 | } | 255 | } |
253 | 256 | ||
@@ -290,6 +293,9 @@ void ieee80211_key_free(struct ieee80211_key *key) | |||
290 | __ieee80211_key_replace(key->sdata, key->sta, | 293 | __ieee80211_key_replace(key->sdata, key->sta, |
291 | key, NULL); | 294 | key, NULL); |
292 | 295 | ||
296 | /* | ||
297 | * Do NOT remove this without looking at sta_info_destroy() | ||
298 | */ | ||
293 | synchronize_rcu(); | 299 | synchronize_rcu(); |
294 | 300 | ||
295 | /* | 301 | /* |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index ebe1a7a80bad..9de1ccc11cf9 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -83,11 +83,10 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, | |||
83 | /** | 83 | /** |
84 | * mesh_accept_plinks_update: update accepting_plink in local mesh beacons | 84 | * mesh_accept_plinks_update: update accepting_plink in local mesh beacons |
85 | * | 85 | * |
86 | * @dev: mesh interface in which mesh beacons are going to be updated | 86 | * @sdata: mesh interface in which mesh beacons are going to be updated |
87 | */ | 87 | */ |
88 | void mesh_accept_plinks_update(struct net_device *dev) | 88 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) |
89 | { | 89 | { |
90 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
91 | bool free_plinks; | 90 | bool free_plinks; |
92 | 91 | ||
93 | /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, | 92 | /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index d565b3fb9e6a..576eee83d859 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -65,9 +65,10 @@ enum mesh_path_flags { | |||
65 | * @state_lock: mesh pat state lock | 65 | * @state_lock: mesh pat state lock |
66 | * | 66 | * |
67 | * | 67 | * |
68 | * The combination of dst and dev is unique in the mesh path table. A reference | 68 | * The combination of dst and dev is unique in the mesh path table. Since the |
69 | * to the next_hop sta will be kept and in case this sta is removed, the | 69 | * next_hop STA is only protected by RCU as well, deleting the STA must also |
70 | * mesh_path structure must be also removed or substitued in a rcu safe way | 70 | * remove/substitute the mesh_path structure and wait until that is no longer |
71 | * reachable before destroying the STA completely. | ||
71 | */ | 72 | */ |
72 | struct mesh_path { | 73 | struct mesh_path { |
73 | u8 dst[ETH_ALEN]; | 74 | u8 dst[ETH_ALEN]; |
@@ -230,8 +231,9 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, | |||
230 | bool add); | 231 | bool add); |
231 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, | 232 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, |
232 | struct net_device *dev); | 233 | struct net_device *dev); |
233 | void mesh_accept_plinks_update(struct net_device *dev); | 234 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); |
234 | struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev); | 235 | struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, |
236 | struct ieee80211_sub_if_data *sdata); | ||
235 | void mesh_plink_broken(struct sta_info *sta); | 237 | void mesh_plink_broken(struct sta_info *sta); |
236 | void mesh_plink_deactivate(struct sta_info *sta); | 238 | void mesh_plink_deactivate(struct sta_info *sta); |
237 | int mesh_plink_open(struct sta_info *sta); | 239 | int mesh_plink_open(struct sta_info *sta); |
@@ -254,7 +256,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath); | |||
254 | void mesh_path_tx_pending(struct mesh_path *mpath); | 256 | void mesh_path_tx_pending(struct mesh_path *mpath); |
255 | int mesh_pathtbl_init(void); | 257 | int mesh_pathtbl_init(void); |
256 | void mesh_pathtbl_unregister(void); | 258 | void mesh_pathtbl_unregister(void); |
257 | int mesh_path_del(u8 *addr, struct net_device *dev); | 259 | int mesh_path_del(u8 *addr, struct net_device *dev, bool force); |
258 | void mesh_path_timer(unsigned long data); | 260 | void mesh_path_timer(unsigned long data); |
259 | void mesh_path_flush_by_nexthop(struct sta_info *sta); | 261 | void mesh_path_flush_by_nexthop(struct sta_info *sta); |
260 | void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev); | 262 | void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev); |
@@ -270,7 +272,7 @@ static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) | |||
270 | 272 | ||
271 | static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) | 273 | static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) |
272 | { | 274 | { |
273 | return (min(mesh_plink_free_count(sdata), | 275 | return (min_t(long, mesh_plink_free_count(sdata), |
274 | MESH_MAX_PLINKS - sdata->local->num_sta)) > 0; | 276 | MESH_MAX_PLINKS - sdata->local->num_sta)) > 0; |
275 | } | 277 | } |
276 | 278 | ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index c2f40ef418cf..d8530fe7a0b3 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -294,7 +294,6 @@ static u32 hwmp_route_info_get(struct net_device *dev, | |||
294 | orig_metric = PREP_IE_METRIC(hwmp_ie); | 294 | orig_metric = PREP_IE_METRIC(hwmp_ie); |
295 | break; | 295 | break; |
296 | default: | 296 | default: |
297 | sta_info_put(sta); | ||
298 | rcu_read_unlock(); | 297 | rcu_read_unlock(); |
299 | return 0; | 298 | return 0; |
300 | } | 299 | } |
@@ -330,7 +329,6 @@ static u32 hwmp_route_info_get(struct net_device *dev, | |||
330 | mpath = mesh_path_lookup(orig_addr, dev); | 329 | mpath = mesh_path_lookup(orig_addr, dev); |
331 | if (!mpath) { | 330 | if (!mpath) { |
332 | rcu_read_unlock(); | 331 | rcu_read_unlock(); |
333 | sta_info_put(sta); | ||
334 | return 0; | 332 | return 0; |
335 | } | 333 | } |
336 | spin_lock_bh(&mpath->state_lock); | 334 | spin_lock_bh(&mpath->state_lock); |
@@ -372,7 +370,6 @@ static u32 hwmp_route_info_get(struct net_device *dev, | |||
372 | mpath = mesh_path_lookup(ta, dev); | 370 | mpath = mesh_path_lookup(ta, dev); |
373 | if (!mpath) { | 371 | if (!mpath) { |
374 | rcu_read_unlock(); | 372 | rcu_read_unlock(); |
375 | sta_info_put(sta); | ||
376 | return 0; | 373 | return 0; |
377 | } | 374 | } |
378 | spin_lock_bh(&mpath->state_lock); | 375 | spin_lock_bh(&mpath->state_lock); |
@@ -391,7 +388,6 @@ static u32 hwmp_route_info_get(struct net_device *dev, | |||
391 | spin_unlock_bh(&mpath->state_lock); | 388 | spin_unlock_bh(&mpath->state_lock); |
392 | } | 389 | } |
393 | 390 | ||
394 | sta_info_put(sta); | ||
395 | rcu_read_unlock(); | 391 | rcu_read_unlock(); |
396 | 392 | ||
397 | return process ? new_metric : 0; | 393 | return process ? new_metric : 0; |
@@ -861,5 +857,5 @@ void mesh_path_timer(unsigned long data) | |||
861 | endmpathtimer: | 857 | endmpathtimer: |
862 | rcu_read_unlock(); | 858 | rcu_read_unlock(); |
863 | if (delete) | 859 | if (delete) |
864 | mesh_path_del(mpath->dst, mpath->dev); | 860 | mesh_path_del(mpath->dst, mpath->dev, false); |
865 | } | 861 | } |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 3cbdbb23d75a..a17f2b299045 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -55,10 +55,7 @@ static DEFINE_RWLOCK(pathtbl_resize_lock); | |||
55 | */ | 55 | */ |
56 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) | 56 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) |
57 | { | 57 | { |
58 | __sta_info_get(sta); | 58 | rcu_assign_pointer(mpath->next_hop, sta); |
59 | if (mpath->next_hop) | ||
60 | sta_info_put(mpath->next_hop); | ||
61 | mpath->next_hop = sta; | ||
62 | } | 59 | } |
63 | 60 | ||
64 | 61 | ||
@@ -236,7 +233,7 @@ void mesh_plink_broken(struct sta_info *sta) | |||
236 | struct mesh_path *mpath; | 233 | struct mesh_path *mpath; |
237 | struct mpath_node *node; | 234 | struct mpath_node *node; |
238 | struct hlist_node *p; | 235 | struct hlist_node *p; |
239 | struct net_device *dev = sta->dev; | 236 | struct net_device *dev = sta->sdata->dev; |
240 | int i; | 237 | int i; |
241 | 238 | ||
242 | rcu_read_lock(); | 239 | rcu_read_lock(); |
@@ -266,9 +263,9 @@ EXPORT_SYMBOL(mesh_plink_broken); | |||
266 | * | 263 | * |
267 | * RCU notes: this function is called when a mesh plink transitions from ESTAB | 264 | * RCU notes: this function is called when a mesh plink transitions from ESTAB |
268 | * to any other state, since ESTAB state is the only one that allows path | 265 | * to any other state, since ESTAB state is the only one that allows path |
269 | * creation. This will happen before the sta can be freed (since we hold | 266 | * creation. This will happen before the sta can be freed (because |
270 | * a reference to it) so any reader in a rcu read block will be protected | 267 | * sta_info_destroy() calls this) so any reader in a rcu read block will be |
271 | * against the plink dissapearing. | 268 | * protected against the plink disappearing. |
272 | */ | 269 | */ |
273 | void mesh_path_flush_by_nexthop(struct sta_info *sta) | 270 | void mesh_path_flush_by_nexthop(struct sta_info *sta) |
274 | { | 271 | { |
@@ -280,7 +277,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) | |||
280 | for_each_mesh_entry(mesh_paths, p, node, i) { | 277 | for_each_mesh_entry(mesh_paths, p, node, i) { |
281 | mpath = node->mpath; | 278 | mpath = node->mpath; |
282 | if (mpath->next_hop == sta) | 279 | if (mpath->next_hop == sta) |
283 | mesh_path_del(mpath->dst, mpath->dev); | 280 | mesh_path_del(mpath->dst, mpath->dev, true); |
284 | } | 281 | } |
285 | } | 282 | } |
286 | 283 | ||
@@ -294,7 +291,7 @@ void mesh_path_flush(struct net_device *dev) | |||
294 | for_each_mesh_entry(mesh_paths, p, node, i) { | 291 | for_each_mesh_entry(mesh_paths, p, node, i) { |
295 | mpath = node->mpath; | 292 | mpath = node->mpath; |
296 | if (mpath->dev == dev) | 293 | if (mpath->dev == dev) |
297 | mesh_path_del(mpath->dst, mpath->dev); | 294 | mesh_path_del(mpath->dst, mpath->dev, false); |
298 | } | 295 | } |
299 | } | 296 | } |
300 | 297 | ||
@@ -303,8 +300,8 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) | |||
303 | struct mpath_node *node = container_of(rp, struct mpath_node, rcu); | 300 | struct mpath_node *node = container_of(rp, struct mpath_node, rcu); |
304 | struct ieee80211_sub_if_data *sdata = | 301 | struct ieee80211_sub_if_data *sdata = |
305 | IEEE80211_DEV_TO_SUB_IF(node->mpath->dev); | 302 | IEEE80211_DEV_TO_SUB_IF(node->mpath->dev); |
306 | if (node->mpath->next_hop) | 303 | |
307 | sta_info_put(node->mpath->next_hop); | 304 | rcu_assign_pointer(node->mpath->next_hop, NULL); |
308 | atomic_dec(&sdata->u.sta.mpaths); | 305 | atomic_dec(&sdata->u.sta.mpaths); |
309 | kfree(node->mpath); | 306 | kfree(node->mpath); |
310 | kfree(node); | 307 | kfree(node); |
@@ -319,9 +316,10 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) | |||
319 | * Returns: 0 if succesful | 316 | * Returns: 0 if succesful |
320 | * | 317 | * |
321 | * State: if the path is being resolved, the deletion will be postponed until | 318 | * State: if the path is being resolved, the deletion will be postponed until |
322 | * the path resolution completes or times out. | 319 | * the path resolution completes or times out, unless the force parameter |
320 | * is given. | ||
323 | */ | 321 | */ |
324 | int mesh_path_del(u8 *addr, struct net_device *dev) | 322 | int mesh_path_del(u8 *addr, struct net_device *dev, bool force) |
325 | { | 323 | { |
326 | struct mesh_path *mpath; | 324 | struct mesh_path *mpath; |
327 | struct mpath_node *node; | 325 | struct mpath_node *node; |
@@ -340,7 +338,7 @@ int mesh_path_del(u8 *addr, struct net_device *dev) | |||
340 | if (mpath->dev == dev && | 338 | if (mpath->dev == dev && |
341 | memcmp(addr, mpath->dst, ETH_ALEN) == 0) { | 339 | memcmp(addr, mpath->dst, ETH_ALEN) == 0) { |
342 | spin_lock_bh(&mpath->state_lock); | 340 | spin_lock_bh(&mpath->state_lock); |
343 | if (mpath->flags & MESH_PATH_RESOLVING) { | 341 | if (!force && mpath->flags & MESH_PATH_RESOLVING) { |
344 | mpath->flags |= MESH_PATH_DELETE; | 342 | mpath->flags |= MESH_PATH_DELETE; |
345 | } else { | 343 | } else { |
346 | mpath->flags |= MESH_PATH_RESOLVING; | 344 | mpath->flags |= MESH_PATH_RESOLVING; |
@@ -510,7 +508,7 @@ void mesh_path_expire(struct net_device *dev) | |||
510 | time_after(jiffies, | 508 | time_after(jiffies, |
511 | mpath->exp_time + MESH_PATH_EXPIRE)) { | 509 | mpath->exp_time + MESH_PATH_EXPIRE)) { |
512 | spin_unlock_bh(&mpath->state_lock); | 510 | spin_unlock_bh(&mpath->state_lock); |
513 | mesh_path_del(mpath->dst, mpath->dev); | 511 | mesh_path_del(mpath->dst, mpath->dev, false); |
514 | } else | 512 | } else |
515 | spin_unlock_bh(&mpath->state_lock); | 513 | spin_unlock_bh(&mpath->state_lock); |
516 | } | 514 | } |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index b5fbe970e48f..c2b80500ae72 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -65,14 +65,14 @@ static inline | |||
65 | void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | 65 | void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) |
66 | { | 66 | { |
67 | atomic_inc(&sdata->u.sta.mshstats.estab_plinks); | 67 | atomic_inc(&sdata->u.sta.mshstats.estab_plinks); |
68 | mesh_accept_plinks_update(sdata->dev); | 68 | mesh_accept_plinks_update(sdata); |
69 | } | 69 | } |
70 | 70 | ||
71 | static inline | 71 | static inline |
72 | void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | 72 | void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) |
73 | { | 73 | { |
74 | atomic_dec(&sdata->u.sta.mshstats.estab_plinks); | 74 | atomic_dec(&sdata->u.sta.mshstats.estab_plinks); |
75 | mesh_accept_plinks_update(sdata->dev); | 75 | mesh_accept_plinks_update(sdata); |
76 | } | 76 | } |
77 | 77 | ||
78 | /** | 78 | /** |
@@ -99,12 +99,13 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) | |||
99 | * | 99 | * |
100 | * Returns: non-NULL on success, ERR_PTR() on error. | 100 | * Returns: non-NULL on success, ERR_PTR() on error. |
101 | */ | 101 | */ |
102 | struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) | 102 | struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, |
103 | struct ieee80211_sub_if_data *sdata) | ||
103 | { | 104 | { |
104 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 105 | struct ieee80211_local *local = sdata->local; |
105 | struct sta_info *sta; | 106 | struct sta_info *sta; |
106 | 107 | ||
107 | if (memcmp(hw_addr, dev->dev_addr, ETH_ALEN) == 0) | 108 | if (compare_ether_addr(hw_addr, sdata->dev->dev_addr) == 0) |
108 | /* never add ourselves as neighbours */ | 109 | /* never add ourselves as neighbours */ |
109 | return ERR_PTR(-EINVAL); | 110 | return ERR_PTR(-EINVAL); |
110 | 111 | ||
@@ -114,7 +115,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) | |||
114 | if (local->num_sta >= MESH_MAX_PLINKS) | 115 | if (local->num_sta >= MESH_MAX_PLINKS) |
115 | return ERR_PTR(-ENOSPC); | 116 | return ERR_PTR(-ENOSPC); |
116 | 117 | ||
117 | sta = sta_info_add(local, dev, hw_addr, GFP_KERNEL); | 118 | sta = sta_info_add(sdata, hw_addr); |
118 | if (IS_ERR(sta)) | 119 | if (IS_ERR(sta)) |
119 | return sta; | 120 | return sta; |
120 | 121 | ||
@@ -125,7 +126,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) | |||
125 | sta->supp_rates[local->hw.conf.channel->band] = rates; | 126 | sta->supp_rates[local->hw.conf.channel->band] = rates; |
126 | rate_control_rate_init(sta, local); | 127 | rate_control_rate_init(sta, local); |
127 | 128 | ||
128 | mesh_accept_plinks_update(dev); | 129 | mesh_accept_plinks_update(sdata); |
129 | 130 | ||
130 | return sta; | 131 | return sta; |
131 | } | 132 | } |
@@ -141,7 +142,8 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) | |||
141 | */ | 142 | */ |
142 | static void __mesh_plink_deactivate(struct sta_info *sta) | 143 | static void __mesh_plink_deactivate(struct sta_info *sta) |
143 | { | 144 | { |
144 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 145 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
146 | |||
145 | if (sta->plink_state == ESTAB) | 147 | if (sta->plink_state == ESTAB) |
146 | mesh_plink_dec_estab_count(sdata); | 148 | mesh_plink_dec_estab_count(sdata); |
147 | sta->plink_state = BLOCKED; | 149 | sta->plink_state = BLOCKED; |
@@ -246,11 +248,15 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, | |||
246 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 248 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
247 | struct sta_info *sta; | 249 | struct sta_info *sta; |
248 | 250 | ||
251 | rcu_read_lock(); | ||
252 | |||
249 | sta = sta_info_get(local, hw_addr); | 253 | sta = sta_info_get(local, hw_addr); |
250 | if (!sta) { | 254 | if (!sta) { |
251 | sta = mesh_plink_add(hw_addr, rates, dev); | 255 | sta = mesh_plink_add(hw_addr, rates, sdata); |
252 | if (IS_ERR(sta)) | 256 | if (IS_ERR(sta)) { |
257 | rcu_read_unlock(); | ||
253 | return; | 258 | return; |
259 | } | ||
254 | } | 260 | } |
255 | 261 | ||
256 | sta->last_rx = jiffies; | 262 | sta->last_rx = jiffies; |
@@ -260,7 +266,7 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, | |||
260 | sdata->u.sta.mshcfg.auto_open_plinks) | 266 | sdata->u.sta.mshcfg.auto_open_plinks) |
261 | mesh_plink_open(sta); | 267 | mesh_plink_open(sta); |
262 | 268 | ||
263 | sta_info_put(sta); | 269 | rcu_read_unlock(); |
264 | } | 270 | } |
265 | 271 | ||
266 | static void mesh_plink_timer(unsigned long data) | 272 | static void mesh_plink_timer(unsigned long data) |
@@ -273,6 +279,11 @@ static void mesh_plink_timer(unsigned long data) | |||
273 | DECLARE_MAC_BUF(mac); | 279 | DECLARE_MAC_BUF(mac); |
274 | #endif | 280 | #endif |
275 | 281 | ||
282 | /* | ||
283 | * This STA is valid because sta_info_destroy() will | ||
284 | * del_timer_sync() this timer after having made sure | ||
285 | * it cannot be readded (by deleting the plink.) | ||
286 | */ | ||
276 | sta = (struct sta_info *) data; | 287 | sta = (struct sta_info *) data; |
277 | 288 | ||
278 | spin_lock_bh(&sta->plink_lock); | 289 | spin_lock_bh(&sta->plink_lock); |
@@ -286,8 +297,8 @@ static void mesh_plink_timer(unsigned long data) | |||
286 | reason = 0; | 297 | reason = 0; |
287 | llid = sta->llid; | 298 | llid = sta->llid; |
288 | plid = sta->plid; | 299 | plid = sta->plid; |
289 | dev = sta->dev; | 300 | sdata = sta->sdata; |
290 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 301 | dev = sdata->dev; |
291 | 302 | ||
292 | switch (sta->plink_state) { | 303 | switch (sta->plink_state) { |
293 | case OPN_RCVD: | 304 | case OPN_RCVD: |
@@ -302,8 +313,7 @@ static void mesh_plink_timer(unsigned long data) | |||
302 | sta->plink_timeout = sta->plink_timeout + | 313 | sta->plink_timeout = sta->plink_timeout + |
303 | rand % sta->plink_timeout; | 314 | rand % sta->plink_timeout; |
304 | ++sta->plink_retries; | 315 | ++sta->plink_retries; |
305 | if (!mod_plink_timer(sta, sta->plink_timeout)) | 316 | mod_plink_timer(sta, sta->plink_timeout); |
306 | __sta_info_get(sta); | ||
307 | spin_unlock_bh(&sta->plink_lock); | 317 | spin_unlock_bh(&sta->plink_lock); |
308 | mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, | 318 | mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, |
309 | 0, 0); | 319 | 0, 0); |
@@ -316,16 +326,14 @@ static void mesh_plink_timer(unsigned long data) | |||
316 | if (!reason) | 326 | if (!reason) |
317 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); | 327 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); |
318 | sta->plink_state = HOLDING; | 328 | sta->plink_state = HOLDING; |
319 | if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) | 329 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
320 | __sta_info_get(sta); | ||
321 | spin_unlock_bh(&sta->plink_lock); | 330 | spin_unlock_bh(&sta->plink_lock); |
322 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, | 331 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, |
323 | reason); | 332 | reason); |
324 | break; | 333 | break; |
325 | case HOLDING: | 334 | case HOLDING: |
326 | /* holding timer */ | 335 | /* holding timer */ |
327 | if (del_timer(&sta->plink_timer)) | 336 | del_timer(&sta->plink_timer); |
328 | sta_info_put(sta); | ||
329 | mesh_plink_fsm_restart(sta); | 337 | mesh_plink_fsm_restart(sta); |
330 | spin_unlock_bh(&sta->plink_lock); | 338 | spin_unlock_bh(&sta->plink_lock); |
331 | break; | 339 | break; |
@@ -333,8 +341,6 @@ static void mesh_plink_timer(unsigned long data) | |||
333 | spin_unlock_bh(&sta->plink_lock); | 341 | spin_unlock_bh(&sta->plink_lock); |
334 | break; | 342 | break; |
335 | } | 343 | } |
336 | |||
337 | sta_info_put(sta); | ||
338 | } | 344 | } |
339 | 345 | ||
340 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | 346 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) |
@@ -343,14 +349,13 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | |||
343 | sta->plink_timer.data = (unsigned long) sta; | 349 | sta->plink_timer.data = (unsigned long) sta; |
344 | sta->plink_timer.function = mesh_plink_timer; | 350 | sta->plink_timer.function = mesh_plink_timer; |
345 | sta->plink_timeout = timeout; | 351 | sta->plink_timeout = timeout; |
346 | __sta_info_get(sta); | ||
347 | add_timer(&sta->plink_timer); | 352 | add_timer(&sta->plink_timer); |
348 | } | 353 | } |
349 | 354 | ||
350 | int mesh_plink_open(struct sta_info *sta) | 355 | int mesh_plink_open(struct sta_info *sta) |
351 | { | 356 | { |
352 | __le16 llid; | 357 | __le16 llid; |
353 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 358 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
354 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 359 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
355 | DECLARE_MAC_BUF(mac); | 360 | DECLARE_MAC_BUF(mac); |
356 | #endif | 361 | #endif |
@@ -360,7 +365,6 @@ int mesh_plink_open(struct sta_info *sta) | |||
360 | sta->llid = llid; | 365 | sta->llid = llid; |
361 | if (sta->plink_state != LISTEN) { | 366 | if (sta->plink_state != LISTEN) { |
362 | spin_unlock_bh(&sta->plink_lock); | 367 | spin_unlock_bh(&sta->plink_lock); |
363 | sta_info_put(sta); | ||
364 | return -EBUSY; | 368 | return -EBUSY; |
365 | } | 369 | } |
366 | sta->plink_state = OPN_SNT; | 370 | sta->plink_state = OPN_SNT; |
@@ -369,7 +373,8 @@ int mesh_plink_open(struct sta_info *sta) | |||
369 | mpl_dbg("Mesh plink: starting establishment with %s\n", | 373 | mpl_dbg("Mesh plink: starting establishment with %s\n", |
370 | print_mac(mac, sta->addr)); | 374 | print_mac(mac, sta->addr)); |
371 | 375 | ||
372 | return mesh_plink_frame_tx(sta->dev, PLINK_OPEN, sta->addr, llid, 0, 0); | 376 | return mesh_plink_frame_tx(sdata->dev, PLINK_OPEN, |
377 | sta->addr, llid, 0, 0); | ||
373 | } | 378 | } |
374 | 379 | ||
375 | void mesh_plink_block(struct sta_info *sta) | 380 | void mesh_plink_block(struct sta_info *sta) |
@@ -386,7 +391,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
386 | 391 | ||
387 | int mesh_plink_close(struct sta_info *sta) | 392 | int mesh_plink_close(struct sta_info *sta) |
388 | { | 393 | { |
389 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 394 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
390 | int llid, plid, reason; | 395 | int llid, plid, reason; |
391 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 396 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
392 | DECLARE_MAC_BUF(mac); | 397 | DECLARE_MAC_BUF(mac); |
@@ -401,13 +406,11 @@ int mesh_plink_close(struct sta_info *sta) | |||
401 | if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) { | 406 | if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) { |
402 | mesh_plink_fsm_restart(sta); | 407 | mesh_plink_fsm_restart(sta); |
403 | spin_unlock_bh(&sta->plink_lock); | 408 | spin_unlock_bh(&sta->plink_lock); |
404 | sta_info_put(sta); | ||
405 | return 0; | 409 | return 0; |
406 | } else if (sta->plink_state == ESTAB) { | 410 | } else if (sta->plink_state == ESTAB) { |
407 | __mesh_plink_deactivate(sta); | 411 | __mesh_plink_deactivate(sta); |
408 | /* The timer should not be running */ | 412 | /* The timer should not be running */ |
409 | if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) | 413 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
410 | __sta_info_get(sta); | ||
411 | } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) | 414 | } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) |
412 | sta->ignore_plink_timer = true; | 415 | sta->ignore_plink_timer = true; |
413 | 416 | ||
@@ -415,15 +418,16 @@ int mesh_plink_close(struct sta_info *sta) | |||
415 | llid = sta->llid; | 418 | llid = sta->llid; |
416 | plid = sta->plid; | 419 | plid = sta->plid; |
417 | spin_unlock_bh(&sta->plink_lock); | 420 | spin_unlock_bh(&sta->plink_lock); |
418 | mesh_plink_frame_tx(sta->dev, PLINK_CLOSE, sta->addr, llid, plid, | 421 | mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid, |
419 | reason); | 422 | plid, reason); |
420 | return 0; | 423 | return 0; |
421 | } | 424 | } |
422 | 425 | ||
423 | void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | 426 | void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, |
424 | size_t len, struct ieee80211_rx_status *rx_status) | 427 | size_t len, struct ieee80211_rx_status *rx_status) |
425 | { | 428 | { |
426 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 429 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
430 | struct ieee80211_local *local = sdata->local; | ||
427 | struct ieee802_11_elems elems; | 431 | struct ieee802_11_elems elems; |
428 | struct sta_info *sta; | 432 | struct sta_info *sta; |
429 | enum plink_event event; | 433 | enum plink_event event; |
@@ -435,7 +439,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
435 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 439 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
436 | DECLARE_MAC_BUF(mac); | 440 | DECLARE_MAC_BUF(mac); |
437 | #endif | 441 | #endif |
438 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
439 | 442 | ||
440 | if (is_multicast_ether_addr(mgmt->da)) { | 443 | if (is_multicast_ether_addr(mgmt->da)) { |
441 | mpl_dbg("Mesh plink: ignore frame from multicast address"); | 444 | mpl_dbg("Mesh plink: ignore frame from multicast address"); |
@@ -474,14 +477,17 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
474 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) | 477 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) |
475 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); | 478 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); |
476 | 479 | ||
480 | rcu_read_lock(); | ||
481 | |||
477 | sta = sta_info_get(local, mgmt->sa); | 482 | sta = sta_info_get(local, mgmt->sa); |
478 | if (!sta && ftype != PLINK_OPEN) { | 483 | if (!sta && ftype != PLINK_OPEN) { |
479 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); | 484 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); |
485 | rcu_read_unlock(); | ||
480 | return; | 486 | return; |
481 | } | 487 | } |
482 | 488 | ||
483 | if (sta && sta->plink_state == BLOCKED) { | 489 | if (sta && sta->plink_state == BLOCKED) { |
484 | sta_info_put(sta); | 490 | rcu_read_unlock(); |
485 | return; | 491 | return; |
486 | } | 492 | } |
487 | 493 | ||
@@ -505,13 +511,15 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
505 | u64 rates; | 511 | u64 rates; |
506 | if (!mesh_plink_free_count(sdata)) { | 512 | if (!mesh_plink_free_count(sdata)) { |
507 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 513 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
514 | rcu_read_unlock(); | ||
508 | return; | 515 | return; |
509 | } | 516 | } |
510 | 517 | ||
511 | rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); | 518 | rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); |
512 | sta = mesh_plink_add(mgmt->sa, rates, dev); | 519 | sta = mesh_plink_add(mgmt->sa, rates, sdata); |
513 | if (IS_ERR(sta)) { | 520 | if (IS_ERR(sta)) { |
514 | mpl_dbg("Mesh plink error: plink table full\n"); | 521 | mpl_dbg("Mesh plink error: plink table full\n"); |
522 | rcu_read_unlock(); | ||
515 | return; | 523 | return; |
516 | } | 524 | } |
517 | event = OPN_ACPT; | 525 | event = OPN_ACPT; |
@@ -521,14 +529,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
521 | switch (ftype) { | 529 | switch (ftype) { |
522 | case PLINK_OPEN: | 530 | case PLINK_OPEN: |
523 | if (!mesh_plink_free_count(sdata) || | 531 | if (!mesh_plink_free_count(sdata) || |
524 | (sta->plid && sta->plid != plid)) | 532 | (sta->plid && sta->plid != plid)) |
525 | event = OPN_IGNR; | 533 | event = OPN_IGNR; |
526 | else | 534 | else |
527 | event = OPN_ACPT; | 535 | event = OPN_ACPT; |
528 | break; | 536 | break; |
529 | case PLINK_CONFIRM: | 537 | case PLINK_CONFIRM: |
530 | if (!mesh_plink_free_count(sdata) || | 538 | if (!mesh_plink_free_count(sdata) || |
531 | (sta->llid != llid || sta->plid != plid)) | 539 | (sta->llid != llid || sta->plid != plid)) |
532 | event = CNF_IGNR; | 540 | event = CNF_IGNR; |
533 | else | 541 | else |
534 | event = CNF_ACPT; | 542 | event = CNF_ACPT; |
@@ -555,7 +563,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
555 | default: | 563 | default: |
556 | mpl_dbg("Mesh plink: unknown frame subtype\n"); | 564 | mpl_dbg("Mesh plink: unknown frame subtype\n"); |
557 | spin_unlock_bh(&sta->plink_lock); | 565 | spin_unlock_bh(&sta->plink_lock); |
558 | sta_info_put(sta); | 566 | rcu_read_unlock(); |
559 | return; | 567 | return; |
560 | } | 568 | } |
561 | } | 569 | } |
@@ -659,8 +667,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
659 | plid, 0); | 667 | plid, 0); |
660 | break; | 668 | break; |
661 | case CNF_ACPT: | 669 | case CNF_ACPT: |
662 | if (del_timer(&sta->plink_timer)) | 670 | del_timer(&sta->plink_timer); |
663 | sta_info_put(sta); | ||
664 | sta->plink_state = ESTAB; | 671 | sta->plink_state = ESTAB; |
665 | mesh_plink_inc_estab_count(sdata); | 672 | mesh_plink_inc_estab_count(sdata); |
666 | spin_unlock_bh(&sta->plink_lock); | 673 | spin_unlock_bh(&sta->plink_lock); |
@@ -693,8 +700,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
693 | plid, reason); | 700 | plid, reason); |
694 | break; | 701 | break; |
695 | case OPN_ACPT: | 702 | case OPN_ACPT: |
696 | if (del_timer(&sta->plink_timer)) | 703 | del_timer(&sta->plink_timer); |
697 | sta_info_put(sta); | ||
698 | sta->plink_state = ESTAB; | 704 | sta->plink_state = ESTAB; |
699 | mesh_plink_inc_estab_count(sdata); | 705 | mesh_plink_inc_estab_count(sdata); |
700 | spin_unlock_bh(&sta->plink_lock); | 706 | spin_unlock_bh(&sta->plink_lock); |
@@ -717,9 +723,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
717 | __mesh_plink_deactivate(sta); | 723 | __mesh_plink_deactivate(sta); |
718 | sta->plink_state = HOLDING; | 724 | sta->plink_state = HOLDING; |
719 | llid = sta->llid; | 725 | llid = sta->llid; |
720 | if (!mod_plink_timer(sta, | 726 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
721 | dot11MeshHoldingTimeout(sdata))) | ||
722 | __sta_info_get(sta); | ||
723 | spin_unlock_bh(&sta->plink_lock); | 727 | spin_unlock_bh(&sta->plink_lock); |
724 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, | 728 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, |
725 | plid, reason); | 729 | plid, reason); |
@@ -738,10 +742,8 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
738 | case HOLDING: | 742 | case HOLDING: |
739 | switch (event) { | 743 | switch (event) { |
740 | case CLS_ACPT: | 744 | case CLS_ACPT: |
741 | if (del_timer(&sta->plink_timer)) { | 745 | if (del_timer(&sta->plink_timer)) |
742 | sta->ignore_plink_timer = 1; | 746 | sta->ignore_plink_timer = 1; |
743 | sta_info_put(sta); | ||
744 | } | ||
745 | mesh_plink_fsm_restart(sta); | 747 | mesh_plink_fsm_restart(sta); |
746 | spin_unlock_bh(&sta->plink_lock); | 748 | spin_unlock_bh(&sta->plink_lock); |
747 | break; | 749 | break; |
@@ -766,5 +768,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
766 | spin_unlock_bh(&sta->plink_lock); | 768 | spin_unlock_bh(&sta->plink_lock); |
767 | break; | 769 | break; |
768 | } | 770 | } |
769 | sta_info_put(sta); | 771 | |
772 | rcu_read_unlock(); | ||
770 | } | 773 | } |
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 217c0f487bba..a1993161de99 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c | |||
@@ -77,7 +77,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, | |||
77 | int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; | 77 | int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; |
78 | int cur = sta->txrate_idx; | 78 | int cur = sta->txrate_idx; |
79 | 79 | ||
80 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 80 | sdata = sta->sdata; |
81 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 81 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
82 | band = sband->band; | 82 | band = sband->band; |
83 | n_bitrates = sband->n_bitrates; | 83 | n_bitrates = sband->n_bitrates; |
@@ -149,7 +149,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, | |||
149 | struct sta_info *sta) | 149 | struct sta_info *sta) |
150 | { | 150 | { |
151 | #ifdef CONFIG_MAC80211_MESH | 151 | #ifdef CONFIG_MAC80211_MESH |
152 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 152 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
153 | #endif | 153 | #endif |
154 | struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; | 154 | struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; |
155 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; | 155 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; |
@@ -249,23 +249,25 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, | |||
249 | unsigned long period; | 249 | unsigned long period; |
250 | struct ieee80211_supported_band *sband; | 250 | struct ieee80211_supported_band *sband; |
251 | 251 | ||
252 | rcu_read_lock(); | ||
253 | |||
252 | sta = sta_info_get(local, hdr->addr1); | 254 | sta = sta_info_get(local, hdr->addr1); |
253 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 255 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
254 | 256 | ||
255 | if (!sta) | 257 | if (!sta) |
256 | return; | 258 | goto unlock; |
257 | 259 | ||
258 | /* Don't update the state if we're not controlling the rate. */ | 260 | /* Don't update the state if we're not controlling the rate. */ |
259 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 261 | sdata = sta->sdata; |
260 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { | 262 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { |
261 | sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; | 263 | sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; |
262 | return; | 264 | goto unlock; |
263 | } | 265 | } |
264 | 266 | ||
265 | /* Ignore all frames that were sent with a different rate than the rate | 267 | /* Ignore all frames that were sent with a different rate than the rate |
266 | * we currently advise mac80211 to use. */ | 268 | * we currently advise mac80211 to use. */ |
267 | if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) | 269 | if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) |
268 | goto ignore; | 270 | goto unlock; |
269 | 271 | ||
270 | spinfo = sta->rate_ctrl_priv; | 272 | spinfo = sta->rate_ctrl_priv; |
271 | spinfo->tx_num_xmit++; | 273 | spinfo->tx_num_xmit++; |
@@ -303,8 +305,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, | |||
303 | if (time_after(jiffies, spinfo->last_sample + period)) | 305 | if (time_after(jiffies, spinfo->last_sample + period)) |
304 | rate_control_pid_sample(pinfo, local, sta); | 306 | rate_control_pid_sample(pinfo, local, sta); |
305 | 307 | ||
306 | ignore: | 308 | unlock: |
307 | sta_info_put(sta); | 309 | rcu_read_unlock(); |
308 | } | 310 | } |
309 | 311 | ||
310 | static void rate_control_pid_get_rate(void *priv, struct net_device *dev, | 312 | static void rate_control_pid_get_rate(void *priv, struct net_device *dev, |
@@ -319,6 +321,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, | |||
319 | int rateidx; | 321 | int rateidx; |
320 | u16 fc; | 322 | u16 fc; |
321 | 323 | ||
324 | rcu_read_lock(); | ||
325 | |||
322 | sta = sta_info_get(local, hdr->addr1); | 326 | sta = sta_info_get(local, hdr->addr1); |
323 | 327 | ||
324 | /* Send management frames and broadcast/multicast data using lowest | 328 | /* Send management frames and broadcast/multicast data using lowest |
@@ -327,8 +331,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, | |||
327 | if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || | 331 | if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || |
328 | is_multicast_ether_addr(hdr->addr1) || !sta) { | 332 | is_multicast_ether_addr(hdr->addr1) || !sta) { |
329 | sel->rate = rate_lowest(local, sband, sta); | 333 | sel->rate = rate_lowest(local, sband, sta); |
330 | if (sta) | 334 | rcu_read_unlock(); |
331 | sta_info_put(sta); | ||
332 | return; | 335 | return; |
333 | } | 336 | } |
334 | 337 | ||
@@ -344,7 +347,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, | |||
344 | 347 | ||
345 | sta->last_txrate_idx = rateidx; | 348 | sta->last_txrate_idx = rateidx; |
346 | 349 | ||
347 | sta_info_put(sta); | 350 | rcu_read_unlock(); |
348 | 351 | ||
349 | sel->rate = &sband->bitrates[rateidx]; | 352 | sel->rate = &sband->bitrates[rateidx]; |
350 | 353 | ||
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index bcc541d4b95c..4f72fdca7f12 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c | |||
@@ -40,7 +40,7 @@ static void rate_control_rate_inc(struct ieee80211_local *local, | |||
40 | int i = sta->txrate_idx; | 40 | int i = sta->txrate_idx; |
41 | int maxrate; | 41 | int maxrate; |
42 | 42 | ||
43 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 43 | sdata = sta->sdata; |
44 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { | 44 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { |
45 | /* forced unicast rate - do not change STA rate */ | 45 | /* forced unicast rate - do not change STA rate */ |
46 | return; | 46 | return; |
@@ -70,7 +70,7 @@ static void rate_control_rate_dec(struct ieee80211_local *local, | |||
70 | struct ieee80211_supported_band *sband; | 70 | struct ieee80211_supported_band *sband; |
71 | int i = sta->txrate_idx; | 71 | int i = sta->txrate_idx; |
72 | 72 | ||
73 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 73 | sdata = sta->sdata; |
74 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { | 74 | if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { |
75 | /* forced unicast rate - do not change STA rate */ | 75 | /* forced unicast rate - do not change STA rate */ |
76 | return; | 76 | return; |
@@ -118,10 +118,12 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, | |||
118 | struct sta_info *sta; | 118 | struct sta_info *sta; |
119 | struct sta_rate_control *srctrl; | 119 | struct sta_rate_control *srctrl; |
120 | 120 | ||
121 | rcu_read_lock(); | ||
122 | |||
121 | sta = sta_info_get(local, hdr->addr1); | 123 | sta = sta_info_get(local, hdr->addr1); |
122 | 124 | ||
123 | if (!sta) | 125 | if (!sta) |
124 | return; | 126 | goto unlock; |
125 | 127 | ||
126 | srctrl = sta->rate_ctrl_priv; | 128 | srctrl = sta->rate_ctrl_priv; |
127 | srctrl->tx_num_xmit++; | 129 | srctrl->tx_num_xmit++; |
@@ -191,7 +193,8 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, | |||
191 | } | 193 | } |
192 | } | 194 | } |
193 | 195 | ||
194 | sta_info_put(sta); | 196 | unlock: |
197 | rcu_read_unlock(); | ||
195 | } | 198 | } |
196 | 199 | ||
197 | 200 | ||
@@ -208,6 +211,8 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, | |||
208 | int rateidx; | 211 | int rateidx; |
209 | u16 fc; | 212 | u16 fc; |
210 | 213 | ||
214 | rcu_read_lock(); | ||
215 | |||
211 | sta = sta_info_get(local, hdr->addr1); | 216 | sta = sta_info_get(local, hdr->addr1); |
212 | 217 | ||
213 | /* Send management frames and broadcast/multicast data using lowest | 218 | /* Send management frames and broadcast/multicast data using lowest |
@@ -216,8 +221,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, | |||
216 | if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || | 221 | if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || |
217 | is_multicast_ether_addr(hdr->addr1) || !sta) { | 222 | is_multicast_ether_addr(hdr->addr1) || !sta) { |
218 | sel->rate = rate_lowest(local, sband, sta); | 223 | sel->rate = rate_lowest(local, sband, sta); |
219 | if (sta) | 224 | rcu_read_unlock(); |
220 | sta_info_put(sta); | ||
221 | return; | 225 | return; |
222 | } | 226 | } |
223 | 227 | ||
@@ -233,7 +237,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, | |||
233 | 237 | ||
234 | sta->last_txrate_idx = rateidx; | 238 | sta->last_txrate_idx = rateidx; |
235 | 239 | ||
236 | sta_info_put(sta); | 240 | rcu_read_unlock(); |
237 | 241 | ||
238 | sel->rate = &sband->bitrates[rateidx]; | 242 | sel->rate = &sband->bitrates[rateidx]; |
239 | } | 243 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2e65ca1cd1aa..8e1e2859bfd5 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -631,7 +631,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) | |||
631 | struct ieee80211_sub_if_data *sdata; | 631 | struct ieee80211_sub_if_data *sdata; |
632 | DECLARE_MAC_BUF(mac); | 632 | DECLARE_MAC_BUF(mac); |
633 | 633 | ||
634 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 634 | sdata = sta->sdata; |
635 | 635 | ||
636 | if (sdata->bss) | 636 | if (sdata->bss) |
637 | atomic_inc(&sdata->bss->num_sta_ps); | 637 | atomic_inc(&sdata->bss->num_sta_ps); |
@@ -652,7 +652,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) | |||
652 | struct ieee80211_tx_packet_data *pkt_data; | 652 | struct ieee80211_tx_packet_data *pkt_data; |
653 | DECLARE_MAC_BUF(mac); | 653 | DECLARE_MAC_BUF(mac); |
654 | 654 | ||
655 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 655 | sdata = sta->sdata; |
656 | 656 | ||
657 | if (sdata->bss) | 657 | if (sdata->bss) |
658 | atomic_dec(&sdata->bss->num_sta_ps); | 658 | atomic_dec(&sdata->bss->num_sta_ps); |
@@ -1287,7 +1287,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1287 | "multicast frame\n", dev->name); | 1287 | "multicast frame\n", dev->name); |
1288 | } else { | 1288 | } else { |
1289 | dsta = sta_info_get(local, skb->data); | 1289 | dsta = sta_info_get(local, skb->data); |
1290 | if (dsta && dsta->dev == dev) { | 1290 | if (dsta && dsta->sdata->dev == dev) { |
1291 | /* | 1291 | /* |
1292 | * The destination station is associated to | 1292 | * The destination station is associated to |
1293 | * this AP (in this VLAN), so send the frame | 1293 | * this AP (in this VLAN), so send the frame |
@@ -1297,8 +1297,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1297 | xmit_skb = skb; | 1297 | xmit_skb = skb; |
1298 | skb = NULL; | 1298 | skb = NULL; |
1299 | } | 1299 | } |
1300 | if (dsta) | ||
1301 | sta_info_put(dsta); | ||
1302 | } | 1300 | } |
1303 | } | 1301 | } |
1304 | 1302 | ||
@@ -1905,13 +1903,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1905 | 1903 | ||
1906 | rx.sta = sta_info_get(local, hdr->addr2); | 1904 | rx.sta = sta_info_get(local, hdr->addr2); |
1907 | if (rx.sta) { | 1905 | if (rx.sta) { |
1908 | rx.dev = rx.sta->dev; | 1906 | rx.sdata = rx.sta->sdata; |
1909 | rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); | 1907 | rx.dev = rx.sta->sdata->dev; |
1910 | } | 1908 | } |
1911 | 1909 | ||
1912 | if ((status->flag & RX_FLAG_MMIC_ERROR)) { | 1910 | if ((status->flag & RX_FLAG_MMIC_ERROR)) { |
1913 | ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); | 1911 | ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); |
1914 | goto end; | 1912 | return; |
1915 | } | 1913 | } |
1916 | 1914 | ||
1917 | if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) | 1915 | if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) |
@@ -1970,10 +1968,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1970 | ieee80211_invoke_rx_handlers(prev, &rx, skb); | 1968 | ieee80211_invoke_rx_handlers(prev, &rx, skb); |
1971 | } else | 1969 | } else |
1972 | dev_kfree_skb(skb); | 1970 | dev_kfree_skb(skb); |
1973 | |||
1974 | end: | ||
1975 | if (rx.sta) | ||
1976 | sta_info_put(rx.sta); | ||
1977 | } | 1971 | } |
1978 | 1972 | ||
1979 | #define SEQ_MODULO 0x1000 | 1973 | #define SEQ_MODULO 0x1000 |
@@ -2150,7 +2144,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2150 | /* if this mpdu is fragmented - terminate rx aggregation session */ | 2144 | /* if this mpdu is fragmented - terminate rx aggregation session */ |
2151 | sc = le16_to_cpu(hdr->seq_ctrl); | 2145 | sc = le16_to_cpu(hdr->seq_ctrl); |
2152 | if (sc & IEEE80211_SCTL_FRAG) { | 2146 | if (sc & IEEE80211_SCTL_FRAG) { |
2153 | ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, | 2147 | ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, |
2154 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); | 2148 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); |
2155 | ret = 1; | 2149 | ret = 1; |
2156 | goto end_reorder; | 2150 | goto end_reorder; |
@@ -2160,9 +2154,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2160 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | 2154 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; |
2161 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, | 2155 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, |
2162 | mpdu_seq_num, 0); | 2156 | mpdu_seq_num, 0); |
2163 | end_reorder: | 2157 | end_reorder: |
2164 | if (sta) | ||
2165 | sta_info_put(sta); | ||
2166 | return ret; | 2158 | return ret; |
2167 | } | 2159 | } |
2168 | 2160 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 81c4e3392f40..ee5b66abc0f1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
16 | #include <linux/if_arp.h> | 16 | #include <linux/if_arp.h> |
17 | #include <linux/timer.h> | 17 | #include <linux/timer.h> |
18 | #include <linux/rtnetlink.h> | ||
18 | 19 | ||
19 | #include <net/mac80211.h> | 20 | #include <net/mac80211.h> |
20 | #include "ieee80211_i.h" | 21 | #include "ieee80211_i.h" |
@@ -23,14 +24,43 @@ | |||
23 | #include "debugfs_sta.h" | 24 | #include "debugfs_sta.h" |
24 | #include "mesh.h" | 25 | #include "mesh.h" |
25 | 26 | ||
26 | /* Caller must hold local->sta_lock */ | 27 | /** |
27 | static void sta_info_hash_add(struct ieee80211_local *local, | 28 | * DOC: STA information lifetime rules |
28 | struct sta_info *sta) | 29 | * |
29 | { | 30 | * STA info structures (&struct sta_info) are managed in a hash table |
30 | sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; | 31 | * for faster lookup and a list for iteration. They are managed using |
31 | local->sta_hash[STA_HASH(sta->addr)] = sta; | 32 | * RCU, i.e. access to the list and hash table is protected by RCU. |
32 | } | 33 | * |
33 | 34 | * STA info structures are always "alive" when they are added with | |
35 | * @sta_info_add() [this may be changed in the future to allow allocating | ||
36 | * outside of a critical section!], they are then added to the hash | ||
37 | * table and list. Therefore, @sta_info_add() must also be RCU protected, | ||
38 | * also, the caller of @sta_info_add() cannot assume that it owns the | ||
39 | * structure. | ||
40 | * | ||
41 | * Because there are debugfs entries for each station, and adding those | ||
42 | * must be able to sleep, it is also possible to "pin" a station entry, | ||
43 | * that means it can be removed from the hash table but not be freed. | ||
44 | * See the comment in @__sta_info_unlink() for more information. | ||
45 | * | ||
46 | * In order to remove a STA info structure, the caller needs to first | ||
47 | * unlink it (@sta_info_unlink()) from the list and hash tables and | ||
48 | * then wait for an RCU synchronisation before it can be freed. Due to | ||
49 | * the pinning and the possibility of multiple callers trying to remove | ||
50 | * the same STA info at the same time, @sta_info_unlink() can clear the | ||
51 | * STA info pointer it is passed to indicate that the STA info is owned | ||
52 | * by somebody else now. | ||
53 | * | ||
54 | * If @sta_info_unlink() did not clear the pointer then the caller owns | ||
55 | * the STA info structure now and is responsible of destroying it with | ||
56 | * a call to @sta_info_destroy(), not before RCU synchronisation, of | ||
57 | * course. Note that sta_info_destroy() must be protected by the RTNL. | ||
58 | * | ||
59 | * In all other cases, there is no concept of ownership on a STA entry, | ||
60 | * each structure is owned by the global hash table/list until it is | ||
61 | * removed. All users of the structure need to be RCU protected so that | ||
62 | * the structure won't be freed before they are done using it. | ||
63 | */ | ||
34 | 64 | ||
35 | /* Caller must hold local->sta_lock */ | 65 | /* Caller must hold local->sta_lock */ |
36 | static int sta_info_hash_del(struct ieee80211_local *local, | 66 | static int sta_info_hash_del(struct ieee80211_local *local, |
@@ -42,46 +72,39 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
42 | if (!s) | 72 | if (!s) |
43 | return -ENOENT; | 73 | return -ENOENT; |
44 | if (s == sta) { | 74 | if (s == sta) { |
45 | local->sta_hash[STA_HASH(sta->addr)] = s->hnext; | 75 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], |
76 | s->hnext); | ||
46 | return 0; | 77 | return 0; |
47 | } | 78 | } |
48 | 79 | ||
49 | while (s->hnext && s->hnext != sta) | 80 | while (s->hnext && s->hnext != sta) |
50 | s = s->hnext; | 81 | s = s->hnext; |
51 | if (s->hnext) { | 82 | if (s->hnext) { |
52 | s->hnext = sta->hnext; | 83 | rcu_assign_pointer(s->hnext, sta->hnext); |
53 | return 0; | 84 | return 0; |
54 | } | 85 | } |
55 | 86 | ||
56 | return -ENOENT; | 87 | return -ENOENT; |
57 | } | 88 | } |
58 | 89 | ||
59 | /* must hold local->sta_lock */ | 90 | /* protected by RCU */ |
60 | static struct sta_info *__sta_info_find(struct ieee80211_local *local, | 91 | static struct sta_info *__sta_info_find(struct ieee80211_local *local, |
61 | u8 *addr) | 92 | u8 *addr) |
62 | { | 93 | { |
63 | struct sta_info *sta; | 94 | struct sta_info *sta; |
64 | 95 | ||
65 | sta = local->sta_hash[STA_HASH(addr)]; | 96 | sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); |
66 | while (sta) { | 97 | while (sta) { |
67 | if (compare_ether_addr(sta->addr, addr) == 0) | 98 | if (compare_ether_addr(sta->addr, addr) == 0) |
68 | break; | 99 | break; |
69 | sta = sta->hnext; | 100 | sta = rcu_dereference(sta->hnext); |
70 | } | 101 | } |
71 | return sta; | 102 | return sta; |
72 | } | 103 | } |
73 | 104 | ||
74 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) | 105 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) |
75 | { | 106 | { |
76 | struct sta_info *sta; | 107 | return __sta_info_find(local, addr); |
77 | |||
78 | read_lock_bh(&local->sta_lock); | ||
79 | sta = __sta_info_find(local, addr); | ||
80 | if (sta) | ||
81 | __sta_info_get(sta); | ||
82 | read_unlock_bh(&local->sta_lock); | ||
83 | |||
84 | return sta; | ||
85 | } | 108 | } |
86 | EXPORT_SYMBOL(sta_info_get); | 109 | EXPORT_SYMBOL(sta_info_get); |
87 | 110 | ||
@@ -91,81 +114,101 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | |||
91 | struct sta_info *sta; | 114 | struct sta_info *sta; |
92 | int i = 0; | 115 | int i = 0; |
93 | 116 | ||
94 | read_lock_bh(&local->sta_lock); | 117 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
95 | list_for_each_entry(sta, &local->sta_list, list) { | ||
96 | if (i < idx) { | 118 | if (i < idx) { |
97 | ++i; | 119 | ++i; |
98 | continue; | 120 | continue; |
99 | } else if (!dev || dev == sta->dev) { | 121 | } else if (!dev || dev == sta->sdata->dev) { |
100 | __sta_info_get(sta); | ||
101 | read_unlock_bh(&local->sta_lock); | ||
102 | return sta; | 122 | return sta; |
103 | } | 123 | } |
104 | } | 124 | } |
105 | read_unlock_bh(&local->sta_lock); | ||
106 | 125 | ||
107 | return NULL; | 126 | return NULL; |
108 | } | 127 | } |
109 | 128 | ||
110 | static void sta_info_release(struct kref *kref) | 129 | void sta_info_destroy(struct sta_info *sta) |
111 | { | 130 | { |
112 | struct sta_info *sta = container_of(kref, struct sta_info, kref); | ||
113 | struct ieee80211_local *local = sta->local; | 131 | struct ieee80211_local *local = sta->local; |
114 | struct sk_buff *skb; | 132 | struct sk_buff *skb; |
115 | int i; | 133 | int i; |
116 | 134 | ||
117 | /* free sta structure; it has already been removed from | 135 | ASSERT_RTNL(); |
118 | * hash table etc. external structures. Make sure that all | 136 | might_sleep(); |
119 | * buffered frames are release (one might have been added | 137 | |
120 | * after sta_info_free() was called). */ | 138 | rate_control_remove_sta_debugfs(sta); |
139 | ieee80211_sta_debugfs_remove(sta); | ||
140 | |||
141 | #ifdef CONFIG_MAC80211_MESH | ||
142 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
143 | mesh_plink_deactivate(sta); | ||
144 | #endif | ||
145 | |||
146 | /* | ||
147 | * NOTE: This will call synchronize_rcu() internally to | ||
148 | * make sure no key references can be in use. We rely on | ||
149 | * that here for the mesh code! | ||
150 | */ | ||
151 | ieee80211_key_free(sta->key); | ||
152 | WARN_ON(sta->key); | ||
153 | |||
154 | #ifdef CONFIG_MAC80211_MESH | ||
155 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
156 | del_timer_sync(&sta->plink_timer); | ||
157 | #endif | ||
158 | |||
121 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | 159 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { |
122 | local->total_ps_buffered--; | 160 | local->total_ps_buffered--; |
123 | dev_kfree_skb_any(skb); | 161 | dev_kfree_skb_any(skb); |
124 | } | 162 | } |
125 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { | 163 | |
164 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
126 | dev_kfree_skb_any(skb); | 165 | dev_kfree_skb_any(skb); |
127 | } | 166 | |
128 | for (i = 0; i < STA_TID_NUM; i++) { | 167 | for (i = 0; i < STA_TID_NUM; i++) { |
129 | del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); | 168 | del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); |
130 | del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); | 169 | del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); |
131 | } | 170 | } |
132 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); | 171 | rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); |
133 | rate_control_put(sta->rate_ctrl); | 172 | rate_control_put(sta->rate_ctrl); |
173 | |||
134 | kfree(sta); | 174 | kfree(sta); |
135 | } | 175 | } |
136 | 176 | ||
137 | 177 | ||
138 | void sta_info_put(struct sta_info *sta) | 178 | /* Caller must hold local->sta_lock */ |
179 | static void sta_info_hash_add(struct ieee80211_local *local, | ||
180 | struct sta_info *sta) | ||
139 | { | 181 | { |
140 | kref_put(&sta->kref, sta_info_release); | 182 | sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; |
183 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta); | ||
141 | } | 184 | } |
142 | EXPORT_SYMBOL(sta_info_put); | ||
143 | |||
144 | 185 | ||
145 | struct sta_info *sta_info_add(struct ieee80211_local *local, | 186 | struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, |
146 | struct net_device *dev, u8 *addr, gfp_t gfp) | 187 | u8 *addr) |
147 | { | 188 | { |
189 | struct ieee80211_local *local = sdata->local; | ||
148 | struct sta_info *sta; | 190 | struct sta_info *sta; |
149 | int i; | 191 | int i; |
150 | DECLARE_MAC_BUF(mac); | 192 | DECLARE_MAC_BUF(mac); |
193 | unsigned long flags; | ||
151 | 194 | ||
152 | sta = kzalloc(sizeof(*sta), gfp); | 195 | sta = kzalloc(sizeof(*sta), GFP_ATOMIC); |
153 | if (!sta) | 196 | if (!sta) |
154 | return ERR_PTR(-ENOMEM); | 197 | return ERR_PTR(-ENOMEM); |
155 | 198 | ||
156 | kref_init(&sta->kref); | 199 | memcpy(sta->addr, addr, ETH_ALEN); |
200 | sta->local = local; | ||
201 | sta->sdata = sdata; | ||
157 | 202 | ||
158 | sta->rate_ctrl = rate_control_get(local->rate_ctrl); | 203 | sta->rate_ctrl = rate_control_get(local->rate_ctrl); |
159 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); | 204 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, |
205 | GFP_ATOMIC); | ||
160 | if (!sta->rate_ctrl_priv) { | 206 | if (!sta->rate_ctrl_priv) { |
161 | rate_control_put(sta->rate_ctrl); | 207 | rate_control_put(sta->rate_ctrl); |
162 | kfree(sta); | 208 | kfree(sta); |
163 | return ERR_PTR(-ENOMEM); | 209 | return ERR_PTR(-ENOMEM); |
164 | } | 210 | } |
165 | 211 | ||
166 | memcpy(sta->addr, addr, ETH_ALEN); | ||
167 | sta->local = local; | ||
168 | sta->dev = dev; | ||
169 | spin_lock_init(&sta->ampdu_mlme.ampdu_rx); | 212 | spin_lock_init(&sta->ampdu_mlme.ampdu_rx); |
170 | spin_lock_init(&sta->ampdu_mlme.ampdu_tx); | 213 | spin_lock_init(&sta->ampdu_mlme.ampdu_tx); |
171 | for (i = 0; i < STA_TID_NUM; i++) { | 214 | for (i = 0; i < STA_TID_NUM; i++) { |
@@ -190,29 +233,26 @@ struct sta_info *sta_info_add(struct ieee80211_local *local, | |||
190 | } | 233 | } |
191 | skb_queue_head_init(&sta->ps_tx_buf); | 234 | skb_queue_head_init(&sta->ps_tx_buf); |
192 | skb_queue_head_init(&sta->tx_filtered); | 235 | skb_queue_head_init(&sta->tx_filtered); |
193 | write_lock_bh(&local->sta_lock); | 236 | spin_lock_irqsave(&local->sta_lock, flags); |
194 | /* mark sta as used (by caller) */ | ||
195 | __sta_info_get(sta); | ||
196 | /* check if STA exists already */ | 237 | /* check if STA exists already */ |
197 | if (__sta_info_find(local, addr)) { | 238 | if (__sta_info_find(local, addr)) { |
198 | write_unlock_bh(&local->sta_lock); | 239 | spin_unlock_irqrestore(&local->sta_lock, flags); |
199 | sta_info_put(sta); | ||
200 | return ERR_PTR(-EEXIST); | 240 | return ERR_PTR(-EEXIST); |
201 | } | 241 | } |
202 | list_add(&sta->list, &local->sta_list); | 242 | list_add(&sta->list, &local->sta_list); |
203 | local->num_sta++; | 243 | local->num_sta++; |
204 | sta_info_hash_add(local, sta); | 244 | sta_info_hash_add(local, sta); |
205 | if (local->ops->sta_notify) { | ||
206 | struct ieee80211_sub_if_data *sdata; | ||
207 | 245 | ||
208 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 246 | /* notify driver */ |
247 | if (local->ops->sta_notify) { | ||
209 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) | 248 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) |
210 | sdata = sdata->u.vlan.ap; | 249 | sdata = sdata->u.vlan.ap; |
211 | 250 | ||
212 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, | 251 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, |
213 | STA_NOTIFY_ADD, addr); | 252 | STA_NOTIFY_ADD, addr); |
214 | } | 253 | } |
215 | write_unlock_bh(&local->sta_lock); | 254 | |
255 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
216 | 256 | ||
217 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 257 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
218 | printk(KERN_DEBUG "%s: Added STA %s\n", | 258 | printk(KERN_DEBUG "%s: Added STA %s\n", |
@@ -252,19 +292,20 @@ static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, | |||
252 | { | 292 | { |
253 | if (bss) | 293 | if (bss) |
254 | __bss_tim_set(bss, sta->aid); | 294 | __bss_tim_set(bss, sta->aid); |
255 | if (sta->local->ops->set_tim) | 295 | if (sta->local->ops->set_tim) { |
296 | sta->local->tim_in_locked_section = true; | ||
256 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); | 297 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); |
298 | sta->local->tim_in_locked_section = false; | ||
299 | } | ||
257 | } | 300 | } |
258 | 301 | ||
259 | void sta_info_set_tim_bit(struct sta_info *sta) | 302 | void sta_info_set_tim_bit(struct sta_info *sta) |
260 | { | 303 | { |
261 | struct ieee80211_sub_if_data *sdata; | 304 | unsigned long flags; |
262 | |||
263 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
264 | 305 | ||
265 | read_lock_bh(&sta->local->sta_lock); | 306 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
266 | __sta_info_set_tim_bit(sdata->bss, sta); | 307 | __sta_info_set_tim_bit(sta->sdata->bss, sta); |
267 | read_unlock_bh(&sta->local->sta_lock); | 308 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
268 | } | 309 | } |
269 | 310 | ||
270 | static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, | 311 | static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, |
@@ -272,93 +313,135 @@ static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, | |||
272 | { | 313 | { |
273 | if (bss) | 314 | if (bss) |
274 | __bss_tim_clear(bss, sta->aid); | 315 | __bss_tim_clear(bss, sta->aid); |
275 | if (sta->local->ops->set_tim) | 316 | if (sta->local->ops->set_tim) { |
317 | sta->local->tim_in_locked_section = true; | ||
276 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); | 318 | sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); |
319 | sta->local->tim_in_locked_section = false; | ||
320 | } | ||
277 | } | 321 | } |
278 | 322 | ||
279 | void sta_info_clear_tim_bit(struct sta_info *sta) | 323 | void sta_info_clear_tim_bit(struct sta_info *sta) |
280 | { | 324 | { |
281 | struct ieee80211_sub_if_data *sdata; | 325 | unsigned long flags; |
282 | |||
283 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
284 | 326 | ||
285 | read_lock_bh(&sta->local->sta_lock); | 327 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
286 | __sta_info_clear_tim_bit(sdata->bss, sta); | 328 | __sta_info_clear_tim_bit(sta->sdata->bss, sta); |
287 | read_unlock_bh(&sta->local->sta_lock); | 329 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
288 | } | 330 | } |
289 | 331 | ||
290 | /* Caller must hold local->sta_lock */ | 332 | /* |
291 | void sta_info_remove(struct sta_info *sta) | 333 | * See comment in __sta_info_unlink, |
334 | * caller must hold local->sta_lock. | ||
335 | */ | ||
336 | static void __sta_info_pin(struct sta_info *sta) | ||
292 | { | 337 | { |
293 | struct ieee80211_local *local = sta->local; | 338 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); |
294 | struct ieee80211_sub_if_data *sdata; | 339 | sta->pin_status = STA_INFO_PIN_STAT_PINNED; |
340 | } | ||
295 | 341 | ||
296 | /* don't do anything if we've been removed already */ | 342 | /* |
297 | if (sta_info_hash_del(local, sta)) | 343 | * See comment in __sta_info_unlink, returns sta if it |
298 | return; | 344 | * needs to be destroyed. |
345 | */ | ||
346 | static struct sta_info *__sta_info_unpin(struct sta_info *sta) | ||
347 | { | ||
348 | struct sta_info *ret = NULL; | ||
349 | unsigned long flags; | ||
299 | 350 | ||
300 | list_del(&sta->list); | 351 | spin_lock_irqsave(&sta->local->sta_lock, flags); |
301 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 352 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && |
302 | if (sta->flags & WLAN_STA_PS) { | 353 | sta->pin_status != STA_INFO_PIN_STAT_PINNED); |
303 | sta->flags &= ~WLAN_STA_PS; | 354 | if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) |
304 | if (sdata->bss) | 355 | ret = sta; |
305 | atomic_dec(&sdata->bss->num_sta_ps); | 356 | sta->pin_status = STA_INFO_PIN_STAT_NORMAL; |
306 | __sta_info_clear_tim_bit(sdata->bss, sta); | 357 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
307 | } | ||
308 | local->num_sta--; | ||
309 | 358 | ||
310 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 359 | return ret; |
311 | mesh_accept_plinks_update(sdata->dev); | ||
312 | } | 360 | } |
313 | 361 | ||
314 | void sta_info_free(struct sta_info *sta) | 362 | static void __sta_info_unlink(struct sta_info **sta) |
315 | { | 363 | { |
316 | struct sk_buff *skb; | 364 | struct ieee80211_local *local = (*sta)->local; |
317 | struct ieee80211_local *local = sta->local; | 365 | struct ieee80211_sub_if_data *sdata = (*sta)->sdata; |
318 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 366 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
319 | 367 | DECLARE_MAC_BUF(mbuf); | |
320 | DECLARE_MAC_BUF(mac); | 368 | #endif |
321 | 369 | /* | |
322 | might_sleep(); | 370 | * pull caller's reference if we're already gone. |
371 | */ | ||
372 | if (sta_info_hash_del(local, *sta)) { | ||
373 | *sta = NULL; | ||
374 | return; | ||
375 | } | ||
323 | 376 | ||
324 | write_lock_bh(&local->sta_lock); | 377 | /* |
325 | sta_info_remove(sta); | 378 | * Also pull caller's reference if the STA is pinned by the |
326 | write_unlock_bh(&local->sta_lock); | 379 | * task that is adding the debugfs entries. In that case, we |
380 | * leave the STA "to be freed". | ||
381 | * | ||
382 | * The rules are not trivial, but not too complex either: | ||
383 | * (1) pin_status is only modified under the sta_lock | ||
384 | * (2) sta_info_debugfs_add_work() will set the status | ||
385 | * to PINNED when it found an item that needs a new | ||
386 | * debugfs directory created. In that case, that item | ||
387 | * must not be freed although all *RCU* users are done | ||
388 | * with it. Hence, we tell the caller of _unlink() | ||
389 | * that the item is already gone (as can happen when | ||
390 | * two tasks try to unlink/destroy at the same time) | ||
391 | * (3) We set the pin_status to DESTROY here when we | ||
392 | * find such an item. | ||
393 | * (4) sta_info_debugfs_add_work() will reset the pin_status | ||
394 | * from PINNED to NORMAL when it is done with the item, | ||
395 | * but will check for DESTROY before resetting it in | ||
396 | * which case it will free the item. | ||
397 | */ | ||
398 | if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { | ||
399 | (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; | ||
400 | *sta = NULL; | ||
401 | return; | ||
402 | } | ||
327 | 403 | ||
328 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 404 | list_del(&(*sta)->list); |
329 | mesh_plink_deactivate(sta); | ||
330 | 405 | ||
331 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | 406 | if ((*sta)->flags & WLAN_STA_PS) { |
332 | local->total_ps_buffered--; | 407 | (*sta)->flags &= ~WLAN_STA_PS; |
333 | dev_kfree_skb(skb); | 408 | if (sdata->bss) |
334 | } | 409 | atomic_dec(&sdata->bss->num_sta_ps); |
335 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { | 410 | __sta_info_clear_tim_bit(sdata->bss, *sta); |
336 | dev_kfree_skb(skb); | ||
337 | } | 411 | } |
338 | 412 | ||
339 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 413 | local->num_sta--; |
340 | printk(KERN_DEBUG "%s: Removed STA %s\n", | ||
341 | wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); | ||
342 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
343 | |||
344 | ieee80211_key_free(sta->key); | ||
345 | WARN_ON(sta->key); | ||
346 | 414 | ||
347 | if (local->ops->sta_notify) { | 415 | if (local->ops->sta_notify) { |
348 | |||
349 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) | 416 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) |
350 | sdata = sdata->u.vlan.ap; | 417 | sdata = sdata->u.vlan.ap; |
351 | 418 | ||
352 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, | 419 | local->ops->sta_notify(local_to_hw(local), &sdata->vif, |
353 | STA_NOTIFY_REMOVE, sta->addr); | 420 | STA_NOTIFY_REMOVE, (*sta)->addr); |
354 | } | 421 | } |
355 | 422 | ||
356 | rate_control_remove_sta_debugfs(sta); | 423 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
357 | ieee80211_sta_debugfs_remove(sta); | 424 | mesh_accept_plinks_update(sdata); |
425 | #ifdef CONFIG_MAC80211_MESH | ||
426 | del_timer(&(*sta)->plink_timer); | ||
427 | #endif | ||
428 | } | ||
358 | 429 | ||
359 | sta_info_put(sta); | 430 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
431 | printk(KERN_DEBUG "%s: Removed STA %s\n", | ||
432 | wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr)); | ||
433 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
360 | } | 434 | } |
361 | 435 | ||
436 | void sta_info_unlink(struct sta_info **sta) | ||
437 | { | ||
438 | struct ieee80211_local *local = (*sta)->local; | ||
439 | unsigned long flags; | ||
440 | |||
441 | spin_lock_irqsave(&local->sta_lock, flags); | ||
442 | __sta_info_unlink(sta); | ||
443 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
444 | } | ||
362 | 445 | ||
363 | static inline int sta_info_buffer_expired(struct ieee80211_local *local, | 446 | static inline int sta_info_buffer_expired(struct ieee80211_local *local, |
364 | struct sta_info *sta, | 447 | struct sta_info *sta, |
@@ -404,7 +487,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
404 | if (!skb) | 487 | if (!skb) |
405 | break; | 488 | break; |
406 | 489 | ||
407 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 490 | sdata = sta->sdata; |
408 | local->total_ps_buffered--; | 491 | local->total_ps_buffered--; |
409 | printk(KERN_DEBUG "Buffered frame expired (STA " | 492 | printk(KERN_DEBUG "Buffered frame expired (STA " |
410 | "%s)\n", print_mac(mac, sta->addr)); | 493 | "%s)\n", print_mac(mac, sta->addr)); |
@@ -421,13 +504,10 @@ static void sta_info_cleanup(unsigned long data) | |||
421 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 504 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
422 | struct sta_info *sta; | 505 | struct sta_info *sta; |
423 | 506 | ||
424 | read_lock_bh(&local->sta_lock); | 507 | rcu_read_lock(); |
425 | list_for_each_entry(sta, &local->sta_list, list) { | 508 | list_for_each_entry_rcu(sta, &local->sta_list, list) |
426 | __sta_info_get(sta); | ||
427 | sta_info_cleanup_expire_buffered(local, sta); | 509 | sta_info_cleanup_expire_buffered(local, sta); |
428 | sta_info_put(sta); | 510 | rcu_read_unlock(); |
429 | } | ||
430 | read_unlock_bh(&local->sta_lock); | ||
431 | 511 | ||
432 | local->sta_cleanup.expires = | 512 | local->sta_cleanup.expires = |
433 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 513 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
@@ -435,37 +515,45 @@ static void sta_info_cleanup(unsigned long data) | |||
435 | } | 515 | } |
436 | 516 | ||
437 | #ifdef CONFIG_MAC80211_DEBUGFS | 517 | #ifdef CONFIG_MAC80211_DEBUGFS |
438 | static void sta_info_debugfs_add_task(struct work_struct *work) | 518 | static void sta_info_debugfs_add_work(struct work_struct *work) |
439 | { | 519 | { |
440 | struct ieee80211_local *local = | 520 | struct ieee80211_local *local = |
441 | container_of(work, struct ieee80211_local, sta_debugfs_add); | 521 | container_of(work, struct ieee80211_local, sta_debugfs_add); |
442 | struct sta_info *sta, *tmp; | 522 | struct sta_info *sta, *tmp; |
523 | unsigned long flags; | ||
443 | 524 | ||
444 | while (1) { | 525 | while (1) { |
445 | sta = NULL; | 526 | sta = NULL; |
446 | read_lock_bh(&local->sta_lock); | 527 | |
528 | spin_lock_irqsave(&local->sta_lock, flags); | ||
447 | list_for_each_entry(tmp, &local->sta_list, list) { | 529 | list_for_each_entry(tmp, &local->sta_list, list) { |
448 | if (!tmp->debugfs.dir) { | 530 | if (!tmp->debugfs.dir) { |
449 | sta = tmp; | 531 | sta = tmp; |
450 | __sta_info_get(sta); | 532 | __sta_info_pin(sta); |
451 | break; | 533 | break; |
452 | } | 534 | } |
453 | } | 535 | } |
454 | read_unlock_bh(&local->sta_lock); | 536 | spin_unlock_irqrestore(&local->sta_lock, flags); |
455 | 537 | ||
456 | if (!sta) | 538 | if (!sta) |
457 | break; | 539 | break; |
458 | 540 | ||
459 | ieee80211_sta_debugfs_add(sta); | 541 | ieee80211_sta_debugfs_add(sta); |
460 | rate_control_add_sta_debugfs(sta); | 542 | rate_control_add_sta_debugfs(sta); |
461 | sta_info_put(sta); | 543 | |
544 | sta = __sta_info_unpin(sta); | ||
545 | |||
546 | if (sta) { | ||
547 | synchronize_rcu(); | ||
548 | sta_info_destroy(sta); | ||
549 | } | ||
462 | } | 550 | } |
463 | } | 551 | } |
464 | #endif | 552 | #endif |
465 | 553 | ||
466 | void sta_info_init(struct ieee80211_local *local) | 554 | void sta_info_init(struct ieee80211_local *local) |
467 | { | 555 | { |
468 | rwlock_init(&local->sta_lock); | 556 | spin_lock_init(&local->sta_lock); |
469 | INIT_LIST_HEAD(&local->sta_list); | 557 | INIT_LIST_HEAD(&local->sta_list); |
470 | 558 | ||
471 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 559 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
@@ -474,7 +562,7 @@ void sta_info_init(struct ieee80211_local *local) | |||
474 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 562 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
475 | 563 | ||
476 | #ifdef CONFIG_MAC80211_DEBUGFS | 564 | #ifdef CONFIG_MAC80211_DEBUGFS |
477 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); | 565 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); |
478 | #endif | 566 | #endif |
479 | } | 567 | } |
480 | 568 | ||
@@ -493,24 +581,29 @@ void sta_info_stop(struct ieee80211_local *local) | |||
493 | /** | 581 | /** |
494 | * sta_info_flush - flush matching STA entries from the STA table | 582 | * sta_info_flush - flush matching STA entries from the STA table |
495 | * @local: local interface data | 583 | * @local: local interface data |
496 | * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs | 584 | * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs |
497 | */ | 585 | */ |
498 | void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) | 586 | void sta_info_flush(struct ieee80211_local *local, |
587 | struct ieee80211_sub_if_data *sdata) | ||
499 | { | 588 | { |
500 | struct sta_info *sta, *tmp; | 589 | struct sta_info *sta, *tmp; |
501 | LIST_HEAD(tmp_list); | 590 | LIST_HEAD(tmp_list); |
591 | unsigned long flags; | ||
502 | 592 | ||
503 | write_lock_bh(&local->sta_lock); | 593 | might_sleep(); |
504 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | ||
505 | if (!dev || dev == sta->dev) { | ||
506 | __sta_info_get(sta); | ||
507 | sta_info_remove(sta); | ||
508 | list_add_tail(&sta->list, &tmp_list); | ||
509 | } | ||
510 | write_unlock_bh(&local->sta_lock); | ||
511 | 594 | ||
512 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) { | 595 | spin_lock_irqsave(&local->sta_lock, flags); |
513 | sta_info_free(sta); | 596 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
514 | sta_info_put(sta); | 597 | if (!sdata || sdata == sta->sdata) { |
598 | __sta_info_unlink(&sta); | ||
599 | if (sta) | ||
600 | list_add_tail(&sta->list, &tmp_list); | ||
601 | } | ||
515 | } | 602 | } |
603 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
604 | |||
605 | synchronize_rcu(); | ||
606 | |||
607 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
608 | sta_info_destroy(sta); | ||
516 | } | 609 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b9dfb6fa893a..787124c253af 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/list.h> | 12 | #include <linux/list.h> |
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/if_ether.h> | 14 | #include <linux/if_ether.h> |
15 | #include <linux/kref.h> | ||
16 | #include "ieee80211_key.h" | 15 | #include "ieee80211_key.h" |
17 | 16 | ||
18 | /** | 17 | /** |
@@ -134,8 +133,14 @@ struct sta_ampdu_mlme { | |||
134 | u8 dialog_token_allocator; | 133 | u8 dialog_token_allocator; |
135 | }; | 134 | }; |
136 | 135 | ||
136 | |||
137 | /* see __sta_info_unlink */ | ||
138 | #define STA_INFO_PIN_STAT_NORMAL 0 | ||
139 | #define STA_INFO_PIN_STAT_PINNED 1 | ||
140 | #define STA_INFO_PIN_STAT_DESTROY 2 | ||
141 | |||
142 | |||
137 | struct sta_info { | 143 | struct sta_info { |
138 | struct kref kref; | ||
139 | struct list_head list; | 144 | struct list_head list; |
140 | struct sta_info *hnext; /* next entry in hash table list */ | 145 | struct sta_info *hnext; /* next entry in hash table list */ |
141 | 146 | ||
@@ -166,8 +171,8 @@ struct sta_info { | |||
166 | /* last rates used to send a frame to this STA */ | 171 | /* last rates used to send a frame to this STA */ |
167 | int last_txrate_idx, last_nonerp_txrate_idx; | 172 | int last_txrate_idx, last_nonerp_txrate_idx; |
168 | 173 | ||
169 | struct net_device *dev; /* which net device is this station associated | 174 | /* sub_if_data this sta belongs to */ |
170 | * to */ | 175 | struct ieee80211_sub_if_data *sdata; |
171 | 176 | ||
172 | struct ieee80211_key *key; | 177 | struct ieee80211_key *key; |
173 | 178 | ||
@@ -199,6 +204,12 @@ struct sta_info { | |||
199 | 204 | ||
200 | u16 listen_interval; | 205 | u16 listen_interval; |
201 | 206 | ||
207 | /* | ||
208 | * for use by the internal lifetime management, | ||
209 | * see __sta_info_unlink | ||
210 | */ | ||
211 | u8 pin_status; | ||
212 | |||
202 | struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities | 213 | struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities |
203 | of this STA */ | 214 | of this STA */ |
204 | struct sta_ampdu_mlme ampdu_mlme; | 215 | struct sta_ampdu_mlme ampdu_mlme; |
@@ -262,25 +273,37 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) | |||
262 | */ | 273 | */ |
263 | #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) | 274 | #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) |
264 | 275 | ||
265 | static inline void __sta_info_get(struct sta_info *sta) | 276 | /* |
266 | { | 277 | * Get a STA info, must have be under RCU read lock. |
267 | kref_get(&sta->kref); | 278 | */ |
268 | } | 279 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr); |
269 | 280 | /* | |
270 | struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); | 281 | * Get STA info by index, BROKEN! |
282 | */ | ||
271 | struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | 283 | struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, |
272 | struct net_device *dev); | 284 | struct net_device *dev); |
273 | void sta_info_put(struct sta_info *sta); | 285 | /* |
274 | struct sta_info *sta_info_add(struct ieee80211_local *local, | 286 | * Add a new STA info, must be under RCU read lock |
275 | struct net_device *dev, u8 *addr, gfp_t gfp); | 287 | * because otherwise the returned reference isn't |
276 | void sta_info_remove(struct sta_info *sta); | 288 | * necessarily valid long enough. |
277 | void sta_info_free(struct sta_info *sta); | 289 | */ |
278 | void sta_info_init(struct ieee80211_local *local); | 290 | struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, |
279 | int sta_info_start(struct ieee80211_local *local); | 291 | u8 *addr); |
280 | void sta_info_stop(struct ieee80211_local *local); | 292 | /* |
281 | void sta_info_flush(struct ieee80211_local *local, struct net_device *dev); | 293 | * Unlink a STA info from the hash table/list. |
294 | * This can NULL the STA pointer if somebody else | ||
295 | * has already unlinked it. | ||
296 | */ | ||
297 | void sta_info_unlink(struct sta_info **sta); | ||
282 | 298 | ||
299 | void sta_info_destroy(struct sta_info *sta); | ||
283 | void sta_info_set_tim_bit(struct sta_info *sta); | 300 | void sta_info_set_tim_bit(struct sta_info *sta); |
284 | void sta_info_clear_tim_bit(struct sta_info *sta); | 301 | void sta_info_clear_tim_bit(struct sta_info *sta); |
285 | 302 | ||
303 | void sta_info_init(struct ieee80211_local *local); | ||
304 | int sta_info_start(struct ieee80211_local *local); | ||
305 | void sta_info_stop(struct ieee80211_local *local); | ||
306 | void sta_info_flush(struct ieee80211_local *local, | ||
307 | struct ieee80211_sub_if_data *sdata); | ||
308 | |||
286 | #endif /* STA_INFO_H */ | 309 | #endif /* STA_INFO_H */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 33e314f3aab7..80f4343a3007 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -327,10 +327,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
327 | } | 327 | } |
328 | total += skb_queue_len(&ap->ps_bc_buf); | 328 | total += skb_queue_len(&ap->ps_bc_buf); |
329 | } | 329 | } |
330 | rcu_read_unlock(); | ||
331 | 330 | ||
332 | read_lock_bh(&local->sta_lock); | 331 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
333 | list_for_each_entry(sta, &local->sta_list, list) { | ||
334 | skb = skb_dequeue(&sta->ps_tx_buf); | 332 | skb = skb_dequeue(&sta->ps_tx_buf); |
335 | if (skb) { | 333 | if (skb) { |
336 | purged++; | 334 | purged++; |
@@ -338,7 +336,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
338 | } | 336 | } |
339 | total += skb_queue_len(&sta->ps_tx_buf); | 337 | total += skb_queue_len(&sta->ps_tx_buf); |
340 | } | 338 | } |
341 | read_unlock_bh(&local->sta_lock); | 339 | |
340 | rcu_read_unlock(); | ||
342 | 341 | ||
343 | local->total_ps_buffered = total; | 342 | local->total_ps_buffered = total; |
344 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", | 343 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", |
@@ -1141,20 +1140,17 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1141 | return 0; | 1140 | return 0; |
1142 | } | 1141 | } |
1143 | 1142 | ||
1143 | rcu_read_lock(); | ||
1144 | |||
1144 | /* initialises tx */ | 1145 | /* initialises tx */ |
1145 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); | 1146 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); |
1146 | 1147 | ||
1147 | if (res_prepare == TX_DROP) { | 1148 | if (res_prepare == TX_DROP) { |
1148 | dev_kfree_skb(skb); | 1149 | dev_kfree_skb(skb); |
1150 | rcu_read_unlock(); | ||
1149 | return 0; | 1151 | return 0; |
1150 | } | 1152 | } |
1151 | 1153 | ||
1152 | /* | ||
1153 | * key references are protected using RCU and this requires that | ||
1154 | * we are in a read-site RCU section during receive processing | ||
1155 | */ | ||
1156 | rcu_read_lock(); | ||
1157 | |||
1158 | sta = tx.sta; | 1154 | sta = tx.sta; |
1159 | tx.channel = local->hw.conf.channel; | 1155 | tx.channel = local->hw.conf.channel; |
1160 | 1156 | ||
@@ -1167,9 +1163,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1167 | 1163 | ||
1168 | skb = tx.skb; /* handlers are allowed to change skb */ | 1164 | skb = tx.skb; /* handlers are allowed to change skb */ |
1169 | 1165 | ||
1170 | if (sta) | ||
1171 | sta_info_put(sta); | ||
1172 | |||
1173 | if (unlikely(res == TX_DROP)) { | 1166 | if (unlikely(res == TX_DROP)) { |
1174 | I802_DEBUG_INC(local->tx_handlers_drop); | 1167 | I802_DEBUG_INC(local->tx_handlers_drop); |
1175 | goto drop; | 1168 | goto drop; |
@@ -1489,11 +1482,11 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1489 | * in AP mode) | 1482 | * in AP mode) |
1490 | */ | 1483 | */ |
1491 | if (!is_multicast_ether_addr(hdr.addr1)) { | 1484 | if (!is_multicast_ether_addr(hdr.addr1)) { |
1485 | rcu_read_lock(); | ||
1492 | sta = sta_info_get(local, hdr.addr1); | 1486 | sta = sta_info_get(local, hdr.addr1); |
1493 | if (sta) { | 1487 | if (sta) |
1494 | sta_flags = sta->flags; | 1488 | sta_flags = sta->flags; |
1495 | sta_info_put(sta); | 1489 | rcu_read_unlock(); |
1496 | } | ||
1497 | } | 1490 | } |
1498 | 1491 | ||
1499 | /* receiver is QoS enabled, use a QoS type frame */ | 1492 | /* receiver is QoS enabled, use a QoS type frame */ |
@@ -1722,7 +1715,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1722 | 1715 | ||
1723 | /* Generate bitmap for TIM only if there are any STAs in power save | 1716 | /* Generate bitmap for TIM only if there are any STAs in power save |
1724 | * mode. */ | 1717 | * mode. */ |
1725 | read_lock_bh(&local->sta_lock); | ||
1726 | if (atomic_read(&bss->num_sta_ps) > 0) | 1718 | if (atomic_read(&bss->num_sta_ps) > 0) |
1727 | /* in the hope that this is faster than | 1719 | /* in the hope that this is faster than |
1728 | * checking byte-for-byte */ | 1720 | * checking byte-for-byte */ |
@@ -1773,7 +1765,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1773 | *pos++ = aid0; /* Bitmap control */ | 1765 | *pos++ = aid0; /* Bitmap control */ |
1774 | *pos++ = 0; /* Part Virt Bitmap */ | 1766 | *pos++ = 0; /* Part Virt Bitmap */ |
1775 | } | 1767 | } |
1776 | read_unlock_bh(&local->sta_lock); | ||
1777 | } | 1768 | } |
1778 | 1769 | ||
1779 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | 1770 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, |
@@ -1821,7 +1812,22 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1821 | ieee80211_include_sequence(sdata, | 1812 | ieee80211_include_sequence(sdata, |
1822 | (struct ieee80211_hdr *)skb->data); | 1813 | (struct ieee80211_hdr *)skb->data); |
1823 | 1814 | ||
1824 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | 1815 | /* |
1816 | * Not very nice, but we want to allow the driver to call | ||
1817 | * ieee80211_beacon_get() as a response to the set_tim() | ||
1818 | * callback. That, however, is already invoked under the | ||
1819 | * sta_lock to guarantee consistent and race-free update | ||
1820 | * of the tim bitmap in mac80211 and the driver. | ||
1821 | */ | ||
1822 | if (local->tim_in_locked_section) { | ||
1823 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1824 | } else { | ||
1825 | unsigned long flags; | ||
1826 | |||
1827 | spin_lock_irqsave(&local->sta_lock, flags); | ||
1828 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1829 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1830 | } | ||
1825 | 1831 | ||
1826 | if (beacon->tail) | 1832 | if (beacon->tail) |
1827 | memcpy(skb_put(skb, beacon->tail_len), | 1833 | memcpy(skb_put(skb, beacon->tail_len), |
@@ -1965,7 +1971,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1965 | rcu_read_unlock(); | 1971 | rcu_read_unlock(); |
1966 | return NULL; | 1972 | return NULL; |
1967 | } | 1973 | } |
1968 | rcu_read_unlock(); | ||
1969 | 1974 | ||
1970 | if (bss->dtim_count != 0) | 1975 | if (bss->dtim_count != 0) |
1971 | return NULL; /* send buffered bc/mc only after DTIM beacon */ | 1976 | return NULL; /* send buffered bc/mc only after DTIM beacon */ |
@@ -2010,8 +2015,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2010 | skb = NULL; | 2015 | skb = NULL; |
2011 | } | 2016 | } |
2012 | 2017 | ||
2013 | if (sta) | 2018 | rcu_read_unlock(); |
2014 | sta_info_put(sta); | ||
2015 | 2019 | ||
2016 | return skb; | 2020 | return skb; |
2017 | } | 2021 | } |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 8cc036decc82..4e94e4026e78 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -153,6 +153,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) | |||
153 | 153 | ||
154 | if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { | 154 | if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { |
155 | queue = pkt_data->queue; | 155 | queue = pkt_data->queue; |
156 | rcu_read_lock(); | ||
156 | sta = sta_info_get(local, hdr->addr1); | 157 | sta = sta_info_get(local, hdr->addr1); |
157 | tid = skb->priority & QOS_CONTROL_TAG1D_MASK; | 158 | tid = skb->priority & QOS_CONTROL_TAG1D_MASK; |
158 | if (sta) { | 159 | if (sta) { |
@@ -164,8 +165,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) | |||
164 | } else { | 165 | } else { |
165 | pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; | 166 | pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; |
166 | } | 167 | } |
167 | sta_info_put(sta); | ||
168 | } | 168 | } |
169 | rcu_read_unlock(); | ||
169 | skb_queue_tail(&q->requeued[queue], skb); | 170 | skb_queue_tail(&q->requeued[queue], skb); |
170 | qd->q.qlen++; | 171 | qd->q.qlen++; |
171 | return 0; | 172 | return 0; |
@@ -187,6 +188,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) | |||
187 | p++; | 188 | p++; |
188 | *p = 0; | 189 | *p = 0; |
189 | 190 | ||
191 | rcu_read_lock(); | ||
192 | |||
190 | sta = sta_info_get(local, hdr->addr1); | 193 | sta = sta_info_get(local, hdr->addr1); |
191 | if (sta) { | 194 | if (sta) { |
192 | int ampdu_queue = sta->tid_to_tx_q[tid]; | 195 | int ampdu_queue = sta->tid_to_tx_q[tid]; |
@@ -197,8 +200,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) | |||
197 | } else { | 200 | } else { |
198 | pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; | 201 | pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; |
199 | } | 202 | } |
200 | sta_info_put(sta); | ||
201 | } | 203 | } |
204 | |||
205 | rcu_read_unlock(); | ||
202 | } | 206 | } |
203 | 207 | ||
204 | if (unlikely(queue >= local->hw.queues)) { | 208 | if (unlikely(queue >= local->hw.queues)) { |