diff options
Diffstat (limited to 'net/mac80211/mesh_hwmp.c')
| -rw-r--r-- | net/mac80211/mesh_hwmp.c | 20 | 
1 files changed, 17 insertions, 3 deletions
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 2aec7c4f357..2b18053070c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -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)) {  |