mac80211: sparse RCU annotations
authorJohannes Berg <johannes.berg@intel.com>
Fri, 13 May 2011 12:15:49 +0000 (14:15 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 16 May 2011 18:10:41 +0000 (14:10 -0400)
This adds sparse RCU annotations to most of
mac80211, only the mesh code remains to be
done.

Due the the previous patches, the annotations
are pretty simple. The only thing that this
actually changes is removing the RCU usage of
key->sta in debugfs since this pointer isn't
actually an RCU-managed pointer (it only has
a single assignment done before the key even
goes live). As that is otherwise harmless, I
decided to make it part of this patch.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
16 files changed:
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs_key.c
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c

index 0c9d0c07eae6cae6ffc6f3ef1f0e91ae64107e2b..9c0d76cdca920ed3b322c4b70ed86f044b4a404b 100644 (file)
@@ -63,7 +63,8 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
-       tid_rx = sta->ampdu_mlme.tid_rx[tid];
+       tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
+                                       lockdep_is_held(&sta->ampdu_mlme.mtx));
 
        if (!tid_rx)
                return;
index f614ee60208919e1ff61a4fc5ed3e17fb82fcfe3..cd5125f77cc5944e9091e443929f9249aeffdf20 100644 (file)
@@ -157,16 +157,19 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                                    bool tx)
 {
        struct ieee80211_local *local = sta->local;
-       struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       struct tid_ampdu_tx *tid_tx;
        int ret;
 
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
-       if (!tid_tx)
-               return -ENOENT;
-
        spin_lock_bh(&sta->lock);
 
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+       if (!tid_tx) {
+               spin_unlock_bh(&sta->lock);
+               return -ENOENT;
+       }
+
        if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
                /* not even started yet! */
                ieee80211_assign_tid_tx(sta, tid, NULL);
@@ -291,13 +294,13 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid)
 
 void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 {
-       struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       struct tid_ampdu_tx *tid_tx;
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        u16 start_seq_num;
        int ret;
 
-       lockdep_assert_held(&sta->ampdu_mlme.mtx);
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
        /*
         * While we're asking the driver about the aggregation,
@@ -404,7 +407,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
                goto err_unlock_sta;
        }
 
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
        /* check if the TID is not in aggregation flow already */
        if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -491,16 +494,19 @@ ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
 static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
                                         struct sta_info *sta, u16 tid)
 {
+       struct tid_ampdu_tx *tid_tx;
+
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
 #endif
 
        drv_ampdu_action(local, sta->sdata,
                         IEEE80211_AMPDU_TX_OPERATIONAL,
-                        &sta->sta, tid, NULL,
-                        sta->ampdu_mlme.tid_tx[tid]->buf_size);
+                        &sta->sta, tid, NULL, tid_tx->buf_size);
 
        /*
         * synchronize with TX path, while splicing the TX path
@@ -508,13 +514,13 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
         */
        spin_lock_bh(&sta->lock);
 
-       ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid);
+       ieee80211_agg_splice_packets(local, tid_tx, tid);
        /*
         * Now mark as operational. This will be visible
         * in the TX path, and lets it go lock-free in
         * the common case.
         */
-       set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state);
+       set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
        ieee80211_agg_splice_finish(local, tid);
 
        spin_unlock_bh(&sta->lock);
@@ -548,7 +554,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        }
 
        mutex_lock(&sta->ampdu_mlme.mtx);
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
        if (WARN_ON(!tid_tx)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -626,7 +632,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
                return -EINVAL;
 
        spin_lock_bh(&sta->lock);
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
        if (!tid_tx) {
                ret = -ENOENT;
@@ -682,7 +688,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 
        mutex_lock(&sta->ampdu_mlme.mtx);
        spin_lock_bh(&sta->lock);
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
 
        if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -763,7 +769,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 
        mutex_lock(&sta->ampdu_mlme.mtx);
 
-       tid_tx = sta->ampdu_mlme.tid_tx[tid];
+       tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
        if (!tid_tx)
                goto out;
 
index 2d1c1a5f3c517faff0fdf572c28e77a10f4fe744..6ecd5862735d9fded8ad3201525ae0031c3cd28e 100644 (file)
@@ -177,11 +177,11 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                        goto out_unlock;
 
                if (pairwise)
-                       key = sta->ptk;
+                       key = key_mtx_dereference(local, sta->ptk);
                else
-                       key = sta->gtk[key_idx];
+                       key = key_mtx_dereference(local, sta->gtk[key_idx]);
        } else
-               key = sdata->keys[key_idx];
+               key = key_mtx_dereference(local, sdata->keys[key_idx]);
 
        if (!key) {
                ret = -ENOENT;
@@ -463,7 +463,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
        int size;
        int err = -EINVAL;
 
-       old = sdata->u.ap.beacon;
+       old = rtnl_dereference(sdata->u.ap.beacon);
 
        /* head must not be zero-length */
        if (params->head && !params->head_len)
@@ -558,8 +558,7 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       old = sdata->u.ap.beacon;
-
+       old = rtnl_dereference(sdata->u.ap.beacon);
        if (old)
                return -EALREADY;
 
@@ -574,8 +573,7 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       old = sdata->u.ap.beacon;
-
+       old = rtnl_dereference(sdata->u.ap.beacon);
        if (!old)
                return -ENOENT;
 
@@ -589,8 +587,7 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       old = sdata->u.ap.beacon;
-
+       old = rtnl_dereference(sdata->u.ap.beacon);
        if (!old)
                return -ENOENT;
 
index f7ef3477c24a13d5eea1cd587266fddaff68da6d..33c58b85c9113b6caaae68b068a68c0df4a01c4c 100644 (file)
@@ -241,16 +241,12 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)
        if (!key->debugfs.dir)
                return;
 
-       rcu_read_lock();
-       sta = rcu_dereference(key->sta);
-       if (sta)
+       sta = key->sta;
+       if (sta) {
                sprintf(buf, "../../stations/%pM", sta->sta.addr);
-       rcu_read_unlock();
-
-       /* using sta as a boolean is fine outside RCU lock */
-       if (sta)
                key->debugfs.stalink =
                        debugfs_create_symlink("station", key->debugfs.dir, buf);
+       }
 
        DEBUGFS_ADD(keylen);
        DEBUGFS_ADD(flags);
@@ -286,7 +282,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
        lockdep_assert_held(&sdata->local->key_mtx);
 
        if (sdata->default_unicast_key) {
-               key = sdata->default_unicast_key;
+               key = key_mtx_dereference(sdata->local,
+                                         sdata->default_unicast_key);
                sprintf(buf, "../keys/%d", key->debugfs.cnt);
                sdata->debugfs.default_unicast_key =
                        debugfs_create_symlink("default_unicast_key",
@@ -297,7 +294,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
        }
 
        if (sdata->default_multicast_key) {
-               key = sdata->default_multicast_key;
+               key = key_mtx_dereference(sdata->local,
+                                         sdata->default_multicast_key);
                sprintf(buf, "../keys/%d", key->debugfs.cnt);
                sdata->debugfs.default_multicast_key =
                        debugfs_create_symlink("default_multicast_key",
@@ -316,9 +314,8 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
        if (!sdata->debugfs.dir)
                return;
 
-       /* this is running under the key lock */
-
-       key = sdata->default_mgmt_key;
+       key = key_mtx_dereference(sdata->local,
+                                 sdata->default_mgmt_key);
        if (key) {
                sprintf(buf, "../keys/%d", key->debugfs.cnt);
                sdata->debugfs.default_mgmt_key =
index 9f5842a43111435ab27eb7f46ed46e929111379c..591add22bcc07e178fe3ffe6215aa2cf84fcf7cc 100644 (file)
@@ -160,7 +160,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
                        continue;
                }
 
-               tid_tx = sta->ampdu_mlme.tid_tx[tid];
+               tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
                if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
                                                 &tid_tx->state))
                        ___ieee80211_stop_tx_ba_session(sta, tid,
index b81860c94698ada410d2b145e0f65aa967d14c00..421eaa6b0c2b36cbb9a1131b78d995a248debaf0 100644 (file)
@@ -662,12 +662,16 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        int tx_last_beacon, len = req->len;
        struct sk_buff *skb;
        struct ieee80211_mgmt *resp;
+       struct sk_buff *presp;
        u8 *pos, *end;
 
        lockdep_assert_held(&ifibss->mtx);
 
+       presp = rcu_dereference_protected(ifibss->presp,
+                                         lockdep_is_held(&ifibss->mtx));
+
        if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||
-           len < 24 + 2 || !ifibss->presp)
+           len < 24 + 2 || !presp)
                return;
 
        tx_last_beacon = drv_tx_last_beacon(local);
@@ -705,7 +709,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        }
 
        /* Reply with ProbeResp */
-       skb = skb_copy(ifibss->presp, GFP_KERNEL);
+       skb = skb_copy(presp, GFP_KERNEL);
        if (!skb)
                return;
 
@@ -985,7 +989,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
 
        /* remove beacon */
        kfree(sdata->u.ibss.ie);
-       skb = sdata->u.ibss.presp;
+       skb = rcu_dereference_protected(sdata->u.ibss.presp,
+                                       lockdep_is_held(&sdata->u.ibss.mtx));
        rcu_assign_pointer(sdata->u.ibss.presp, NULL);
        sdata->vif.bss_conf.ibss_joined = false;
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
index 82f90ff8bb18a0833f20bb663318e9eb2cf11e4e..ed755889645dd389896bed344c547e59659adeb9 100644 (file)
@@ -214,7 +214,7 @@ struct beacon_data {
 };
 
 struct ieee80211_if_ap {
-       struct beacon_data *beacon;
+       struct beacon_data __rcu *beacon;
 
        struct list_head vlans;
 
@@ -237,7 +237,7 @@ struct ieee80211_if_vlan {
        struct list_head list;
 
        /* used for all tx if the VLAN is configured to 4-addr mode */
-       struct sta_info *sta;
+       struct sta_info __rcu *sta;
 };
 
 struct mesh_stats {
@@ -442,7 +442,8 @@ struct ieee80211_if_ibss {
 
        unsigned long ibss_join_req;
        /* probe response/beacon for IBSS */
-       struct sk_buff *presp, *skb;
+       struct sk_buff __rcu *presp;
+       struct sk_buff *skb;
 
        enum {
                IEEE80211_IBSS_MLME_SEARCH,
@@ -567,9 +568,10 @@ struct ieee80211_sub_if_data {
        struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
        unsigned int fragment_next;
 
-       struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
-       struct ieee80211_key *default_unicast_key, *default_multicast_key;
-       struct ieee80211_key *default_mgmt_key;
+       struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
+       struct ieee80211_key __rcu *default_unicast_key;
+       struct ieee80211_key __rcu *default_multicast_key;
+       struct ieee80211_key __rcu *default_mgmt_key;
 
        u16 sequence_number;
        __be16 control_port_protocol;
@@ -805,7 +807,7 @@ struct ieee80211_local {
        spinlock_t sta_lock;
        unsigned long num_sta;
        struct list_head sta_list, sta_pending_list;
-       struct sta_info *sta_hash[STA_HASH_SIZE];
+       struct sta_info __rcu *sta_hash[STA_HASH_SIZE];
        struct timer_list sta_cleanup;
        struct work_struct sta_finish_work;
        int sta_generation;
index 4054399be907f8be54d07cf786afc5693e562982..0d00ac93d95823b8e1559d0f0310d8ff93d3a301 100644 (file)
@@ -449,7 +449,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        /* APs need special treatment */
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
-               struct beacon_data *old_beacon = sdata->u.ap.beacon;
+               struct beacon_data *old_beacon =
+                       rtnl_dereference(sdata->u.ap.beacon);
 
                /* sdata_running will return false, so this will disable */
                ieee80211_bss_info_change_notify(sdata,
index 958832dd4f0a43470400d774ae63051eda537f79..31afd712930df2a7507505a26cd24f4f4e1ee2bd 100644 (file)
@@ -195,7 +195,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
        assert_key_lock(sdata->local);
 
        if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
-               key = sdata->keys[idx];
+               key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 
        if (uni)
                rcu_assign_pointer(sdata->default_unicast_key, key);
@@ -222,7 +222,7 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
 
        if (idx >= NUM_DEFAULT_KEYS &&
            idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
-               key = sdata->keys[idx];
+               key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 
        rcu_assign_pointer(sdata->default_mgmt_key, key);
 
@@ -266,9 +266,15 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                else
                        idx = new->conf.keyidx;
 
-               defunikey = old && sdata->default_unicast_key == old;
-               defmultikey = old && sdata->default_multicast_key == old;
-               defmgmtkey = old && sdata->default_mgmt_key == old;
+               defunikey = old &&
+                       old == key_mtx_dereference(sdata->local,
+                                               sdata->default_unicast_key);
+               defmultikey = old &&
+                       old == key_mtx_dereference(sdata->local,
+                                               sdata->default_multicast_key);
+               defmgmtkey = old &&
+                       old == key_mtx_dereference(sdata->local,
+                                               sdata->default_mgmt_key);
 
                if (defunikey && !new)
                        __ieee80211_set_default_key(sdata, -1, true, false);
@@ -451,11 +457,11 @@ int ieee80211_key_link(struct ieee80211_key *key,
        mutex_lock(&sdata->local->key_mtx);
 
        if (sta && pairwise)
-               old_key = sta->ptk;
+               old_key = key_mtx_dereference(sdata->local, sta->ptk);
        else if (sta)
-               old_key = sta->gtk[idx];
+               old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
        else
-               old_key = sdata->keys[idx];
+               old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 
        __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
        __ieee80211_key_destroy(old_key);
index e5432ef8b203ce16134d37f3408c73923559d0b2..d801d5351336e608ee0efbdc5efc727d9be00691 100644 (file)
@@ -146,4 +146,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
 void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
 void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
 
+#define key_mtx_dereference(local, ref) \
+       rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
+
 #endif /* IEEE80211_KEY_H */
index 79a2281678bff43c529bf6e70c1864eeab6e6d1d..0d7b08db8e564e07e953b1a501bc97a0e41a6db6 100644 (file)
@@ -871,8 +871,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
         * and we need some headroom for passing the frame to monitor
         * interfaces, but never both at the same time.
         */
+#ifndef __CHECKER__
        BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM !=
                        sizeof(struct ieee80211_tx_status_rtap_hdr));
+#endif
        local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
                                   sizeof(struct ieee80211_tx_status_rtap_hdr));
 
index 5c0c20389a1ada5733e19e264d55a50ec3ae2f9a..e7c5fddb480400a8d61c08b577d093ff32b3b22b 100644 (file)
@@ -92,7 +92,7 @@ struct mesh_path {
        u8 dst[ETH_ALEN];
        u8 mpp[ETH_ALEN];       /* used for MPP or MAP */
        struct ieee80211_sub_if_data *sdata;
-       struct sta_info *next_hop;
+       struct sta_info __rcu *next_hop;
        struct timer_list timer;
        struct sk_buff_head frame_queue;
        struct rcu_head rcu;
index 2aec7c4f357b53248ae47982d7b8bf420c2bd683..2b18053070c1d45c08b8b9c7f1711f84006134a0 100644 (file)
@@ -560,6 +560,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 }
 
 
+static inline struct sta_info *
+next_hop_deref_protected(struct mesh_path *mpath)
+{
+       return rcu_dereference_protected(mpath->next_hop,
+                                        lockdep_is_held(&mpath->state_lock));
+}
+
+
 static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_mgmt *mgmt,
                                    u8 *prep_elem, u32 metric)
@@ -599,7 +607,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
                spin_unlock_bh(&mpath->state_lock);
                goto fail;
        }
-       memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
+       memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN);
        spin_unlock_bh(&mpath->state_lock);
        --ttl;
        flags = PREP_IE_FLAGS(prep_elem);
@@ -651,7 +659,8 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
        if (mpath) {
                spin_lock_bh(&mpath->state_lock);
                if (mpath->flags & MESH_PATH_ACTIVE &&
-                   memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 &&
+                   memcmp(ta, next_hop_deref_protected(mpath)->sta.addr,
+                                                       ETH_ALEN) == 0 &&
                    (!(mpath->flags & MESH_PATH_SN_VALID) ||
                    SN_GT(target_sn, mpath->sn))) {
                        mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -913,6 +922,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 {
        struct sk_buff *skb_to_free = NULL;
        struct mesh_path *mpath;
+       struct sta_info *next_hop;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        u8 *target_addr = hdr->addr3;
        int err = 0;
@@ -940,7 +950,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                        mesh_queue_preq(mpath,
                                        PREQ_Q_F_START | PREQ_Q_F_REFRESH);
                }
-               memcpy(hdr->addr1, mpath->next_hop->sta.addr, ETH_ALEN);
+               next_hop = rcu_dereference(mpath->next_hop);
+               if (next_hop)
+                       memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
+               else
+                       err = -ENOENT;
        } else {
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
                if (!(mpath->flags & MESH_PATH_RESOLVING)) {
index cba8309e9aceb295b31a0444ce2bb34efb9e9c44..82ab6b4643fcdff48624aa46925e286f4d3b7d03 100644 (file)
@@ -67,7 +67,8 @@ static int sta_info_hash_del(struct ieee80211_local *local,
 {
        struct sta_info *s;
 
-       s = local->sta_hash[STA_HASH(sta->sta.addr)];
+       s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)],
+                                     lockdep_is_held(&local->sta_lock));
        if (!s)
                return -ENOENT;
        if (s == sta) {
@@ -76,9 +77,11 @@ static int sta_info_hash_del(struct ieee80211_local *local,
                return 0;
        }
 
-       while (s->hnext && s->hnext != sta)
-               s = s->hnext;
-       if (s->hnext) {
+       while (rcu_access_pointer(s->hnext) &&
+              rcu_access_pointer(s->hnext) != sta)
+               s = rcu_dereference_protected(s->hnext,
+                                       lockdep_is_held(&local->sta_lock));
+       if (rcu_access_pointer(s->hnext)) {
                rcu_assign_pointer(s->hnext, sta->hnext);
                return 0;
        }
@@ -654,9 +657,9 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
 
        mutex_lock(&local->key_mtx);
        for (i = 0; i < NUM_DEFAULT_KEYS; i++)
-               __ieee80211_key_free(sta->gtk[i]);
+               __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
        if (sta->ptk)
-               __ieee80211_key_free(sta->ptk);
+               __ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
        mutex_unlock(&local->key_mtx);
 
        sta->dead = true;
index 55c51855ceb7bd8112d8ca8e9fc1e8b2ba8680dc..d6b566076f051d066fc19a0ff4c268c24e41b8d1 100644 (file)
@@ -164,11 +164,11 @@ struct tid_ampdu_rx {
 struct sta_ampdu_mlme {
        struct mutex mtx;
        /* rx */
-       struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
+       struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM];
        unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];
        /* tx */
        struct work_struct work;
-       struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
+       struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM];
        struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM];
        u8 addba_req_num[STA_TID_NUM];
        u8 dialog_token_allocator;
@@ -243,11 +243,11 @@ struct sta_ampdu_mlme {
 struct sta_info {
        /* General information, mostly static */
        struct list_head list;
-       struct sta_info *hnext;
+       struct sta_info __rcu *hnext;
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
-       struct ieee80211_key *ptk;
+       struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
+       struct ieee80211_key __rcu *ptk;
        struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
        spinlock_t lock;
@@ -403,6 +403,13 @@ static inline u32 get_sta_flags(struct sta_info *sta)
 void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
                             struct tid_ampdu_tx *tid_tx);
 
+static inline struct tid_ampdu_tx *
+rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
+{
+       return rcu_dereference_protected(sta->ampdu_mlme.tid_tx[tid],
+                                        lockdep_is_held(&sta->lock) ||
+                                        lockdep_is_held(&sta->ampdu_mlme.mtx));
+}
 
 #define STA_HASH_SIZE 256
 #define STA_HASH(sta) (sta[5])
index c9f12113ca6a505e7bbf9fa36ca865ba5cd190b7..6eeaaa2bbafe21d6054c5e6963ca7302a48f7f1c 100644 (file)
@@ -1147,7 +1147,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
                 *     packet pass through because splicing the frames
                 *     back is already done.
                 */
-               tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
+               tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid);
 
                if (!tid_tx) {
                        /* do nothing, let packet pass through */