aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh_plink.c
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2012-10-28 14:28:52 -0400
committerJiri Kosina <jkosina@suse.cz>2012-10-28 14:29:19 -0400
commit3bd7bf1f0fe14f591c089ae61bbfa9bd356f178a (patch)
tree0058693cc9e70b7461dae551f8a19aff2efd13ca /net/mac80211/mesh_plink.c
parentf16f84937d769c893492160b1a8c3672e3992beb (diff)
parente657e078d3dfa9f96976db7a2b5fd7d7c9f1f1a6 (diff)
Merge branch 'master' into for-next
Sync up with Linus' tree to be able to apply Cesar's patch against newer version of the code. Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r--net/mac80211/mesh_plink.c85
1 files changed, 48 insertions, 37 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index af671b984df3..3ab34d816897 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -48,17 +48,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
48 u8 *da, __le16 llid, __le16 plid, __le16 reason); 48 u8 *da, __le16 llid, __le16 plid, __le16 reason);
49 49
50static inline 50static inline
51void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) 51u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
52{ 52{
53 atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); 53 atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
54 mesh_accept_plinks_update(sdata); 54 return mesh_accept_plinks_update(sdata);
55} 55}
56 56
57static inline 57static inline
58void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) 58u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
59{ 59{
60 atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); 60 atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
61 mesh_accept_plinks_update(sdata); 61 return mesh_accept_plinks_update(sdata);
62} 62}
63 63
64/** 64/**
@@ -117,7 +117,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
117 u16 ht_opmode; 117 u16 ht_opmode;
118 bool non_ht_sta = false, ht20_sta = false; 118 bool non_ht_sta = false, ht20_sta = false;
119 119
120 if (local->_oper_channel_type == NL80211_CHAN_NO_HT) 120 if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
121 return 0; 121 return 0;
122 122
123 rcu_read_lock(); 123 rcu_read_lock();
@@ -147,7 +147,8 @@ out:
147 147
148 if (non_ht_sta) 148 if (non_ht_sta)
149 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; 149 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
150 else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20) 150 else if (ht20_sta &&
151 sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20)
151 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; 152 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
152 else 153 else
153 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; 154 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
@@ -170,22 +171,21 @@ out:
170 * @sta: mesh peer link to deactivate 171 * @sta: mesh peer link to deactivate
171 * 172 *
172 * All mesh paths with this peer as next hop will be flushed 173 * All mesh paths with this peer as next hop will be flushed
174 * Returns beacon changed flag if the beacon content changed.
173 * 175 *
174 * Locking: the caller must hold sta->lock 176 * Locking: the caller must hold sta->lock
175 */ 177 */
176static bool __mesh_plink_deactivate(struct sta_info *sta) 178static u32 __mesh_plink_deactivate(struct sta_info *sta)
177{ 179{
178 struct ieee80211_sub_if_data *sdata = sta->sdata; 180 struct ieee80211_sub_if_data *sdata = sta->sdata;
179 bool deactivated = false; 181 u32 changed = 0;
180 182
181 if (sta->plink_state == NL80211_PLINK_ESTAB) { 183 if (sta->plink_state == NL80211_PLINK_ESTAB)
182 mesh_plink_dec_estab_count(sdata); 184 changed = mesh_plink_dec_estab_count(sdata);
183 deactivated = true;
184 }
185 sta->plink_state = NL80211_PLINK_BLOCKED; 185 sta->plink_state = NL80211_PLINK_BLOCKED;
186 mesh_path_flush_by_nexthop(sta); 186 mesh_path_flush_by_nexthop(sta);
187 187
188 return deactivated; 188 return changed;
189} 189}
190 190
191/** 191/**
@@ -198,18 +198,17 @@ static bool __mesh_plink_deactivate(struct sta_info *sta)
198void mesh_plink_deactivate(struct sta_info *sta) 198void mesh_plink_deactivate(struct sta_info *sta)
199{ 199{
200 struct ieee80211_sub_if_data *sdata = sta->sdata; 200 struct ieee80211_sub_if_data *sdata = sta->sdata;
201 bool deactivated; 201 u32 changed;
202 202
203 spin_lock_bh(&sta->lock); 203 spin_lock_bh(&sta->lock);
204 deactivated = __mesh_plink_deactivate(sta); 204 changed = __mesh_plink_deactivate(sta);
205 sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED); 205 sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
206 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, 206 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
207 sta->sta.addr, sta->llid, sta->plid, 207 sta->sta.addr, sta->llid, sta->plid,
208 sta->reason); 208 sta->reason);
209 spin_unlock_bh(&sta->lock); 209 spin_unlock_bh(&sta->lock);
210 210
211 if (deactivated) 211 ieee80211_bss_info_change_notify(sdata, changed);
212 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
213} 212}
214 213
215static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, 214static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
@@ -217,12 +216,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
217 u8 *da, __le16 llid, __le16 plid, __le16 reason) { 216 u8 *da, __le16 llid, __le16 plid, __le16 reason) {
218 struct ieee80211_local *local = sdata->local; 217 struct ieee80211_local *local = sdata->local;
219 struct sk_buff *skb; 218 struct sk_buff *skb;
219 struct ieee80211_tx_info *info;
220 struct ieee80211_mgmt *mgmt; 220 struct ieee80211_mgmt *mgmt;
221 bool include_plid = false; 221 bool include_plid = false;
222 u16 peering_proto = 0; 222 u16 peering_proto = 0;
223 u8 *pos, ie_len = 4; 223 u8 *pos, ie_len = 4;
224 int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) + 224 int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
225 sizeof(mgmt->u.action.u.self_prot); 225 sizeof(mgmt->u.action.u.self_prot);
226 int err = -ENOMEM;
226 227
227 skb = dev_alloc_skb(local->tx_headroom + 228 skb = dev_alloc_skb(local->tx_headroom +
228 hdr_len + 229 hdr_len +
@@ -238,6 +239,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
238 sdata->u.mesh.ie_len); 239 sdata->u.mesh.ie_len);
239 if (!skb) 240 if (!skb)
240 return -1; 241 return -1;
242 info = IEEE80211_SKB_CB(skb);
241 skb_reserve(skb, local->tx_headroom); 243 skb_reserve(skb, local->tx_headroom);
242 mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len); 244 mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
243 memset(mgmt, 0, hdr_len); 245 memset(mgmt, 0, hdr_len);
@@ -258,15 +260,18 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
258 pos = skb_put(skb, 2); 260 pos = skb_put(skb, 2);
259 memcpy(pos + 2, &plid, 2); 261 memcpy(pos + 2, &plid, 2);
260 } 262 }
261 if (ieee80211_add_srates_ie(sdata, skb, true) || 263 if (ieee80211_add_srates_ie(sdata, skb, true,
262 ieee80211_add_ext_srates_ie(sdata, skb, true) || 264 local->oper_channel->band) ||
265 ieee80211_add_ext_srates_ie(sdata, skb, true,
266 local->oper_channel->band) ||
263 mesh_add_rsn_ie(skb, sdata) || 267 mesh_add_rsn_ie(skb, sdata) ||
264 mesh_add_meshid_ie(skb, sdata) || 268 mesh_add_meshid_ie(skb, sdata) ||
265 mesh_add_meshconf_ie(skb, sdata)) 269 mesh_add_meshconf_ie(skb, sdata))
266 return -1; 270 goto free;
267 } else { /* WLAN_SP_MESH_PEERING_CLOSE */ 271 } else { /* WLAN_SP_MESH_PEERING_CLOSE */
272 info->flags |= IEEE80211_TX_CTL_NO_ACK;
268 if (mesh_add_meshid_ie(skb, sdata)) 273 if (mesh_add_meshid_ie(skb, sdata))
269 return -1; 274 goto free;
270 } 275 }
271 276
272 /* Add Mesh Peering Management element */ 277 /* Add Mesh Peering Management element */
@@ -285,11 +290,12 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
285 ie_len += 2; /* reason code */ 290 ie_len += 2; /* reason code */
286 break; 291 break;
287 default: 292 default:
288 return -EINVAL; 293 err = -EINVAL;
294 goto free;
289 } 295 }
290 296
291 if (WARN_ON(skb_tailroom(skb) < 2 + ie_len)) 297 if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
292 return -ENOMEM; 298 goto free;
293 299
294 pos = skb_put(skb, 2 + ie_len); 300 pos = skb_put(skb, 2 + ie_len);
295 *pos++ = WLAN_EID_PEER_MGMT; 301 *pos++ = WLAN_EID_PEER_MGMT;
@@ -310,14 +316,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
310 if (action != WLAN_SP_MESH_PEERING_CLOSE) { 316 if (action != WLAN_SP_MESH_PEERING_CLOSE) {
311 if (mesh_add_ht_cap_ie(skb, sdata) || 317 if (mesh_add_ht_cap_ie(skb, sdata) ||
312 mesh_add_ht_oper_ie(skb, sdata)) 318 mesh_add_ht_oper_ie(skb, sdata))
313 return -1; 319 goto free;
314 } 320 }
315 321
316 if (mesh_add_vendor_ies(skb, sdata)) 322 if (mesh_add_vendor_ies(skb, sdata))
317 return -1; 323 goto free;
318 324
319 ieee80211_tx_skb(sdata, skb); 325 ieee80211_tx_skb(sdata, skb);
320 return 0; 326 return 0;
327free:
328 kfree_skb(skb);
329 return err;
321} 330}
322 331
323/** 332/**
@@ -362,9 +371,14 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
362 371
363 spin_lock_bh(&sta->lock); 372 spin_lock_bh(&sta->lock);
364 sta->last_rx = jiffies; 373 sta->last_rx = jiffies;
374 if (sta->plink_state == NL80211_PLINK_ESTAB) {
375 spin_unlock_bh(&sta->lock);
376 return sta;
377 }
378
365 sta->sta.supp_rates[band] = rates; 379 sta->sta.supp_rates[band] = rates;
366 if (elems->ht_cap_elem && 380 if (elems->ht_cap_elem &&
367 sdata->local->_oper_channel_type != NL80211_CHAN_NO_HT) 381 sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT)
368 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, 382 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
369 elems->ht_cap_elem, 383 elems->ht_cap_elem,
370 &sta->sta.ht_cap); 384 &sta->sta.ht_cap);
@@ -523,7 +537,8 @@ int mesh_plink_open(struct sta_info *sta)
523 spin_lock_bh(&sta->lock); 537 spin_lock_bh(&sta->lock);
524 get_random_bytes(&llid, 2); 538 get_random_bytes(&llid, 2);
525 sta->llid = llid; 539 sta->llid = llid;
526 if (sta->plink_state != NL80211_PLINK_LISTEN) { 540 if (sta->plink_state != NL80211_PLINK_LISTEN &&
541 sta->plink_state != NL80211_PLINK_BLOCKED) {
527 spin_unlock_bh(&sta->lock); 542 spin_unlock_bh(&sta->lock);
528 return -EBUSY; 543 return -EBUSY;
529 } 544 }
@@ -541,15 +556,14 @@ int mesh_plink_open(struct sta_info *sta)
541void mesh_plink_block(struct sta_info *sta) 556void mesh_plink_block(struct sta_info *sta)
542{ 557{
543 struct ieee80211_sub_if_data *sdata = sta->sdata; 558 struct ieee80211_sub_if_data *sdata = sta->sdata;
544 bool deactivated; 559 u32 changed;
545 560
546 spin_lock_bh(&sta->lock); 561 spin_lock_bh(&sta->lock);
547 deactivated = __mesh_plink_deactivate(sta); 562 changed = __mesh_plink_deactivate(sta);
548 sta->plink_state = NL80211_PLINK_BLOCKED; 563 sta->plink_state = NL80211_PLINK_BLOCKED;
549 spin_unlock_bh(&sta->lock); 564 spin_unlock_bh(&sta->lock);
550 565
551 if (deactivated) 566 ieee80211_bss_info_change_notify(sdata, changed);
552 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
553} 567}
554 568
555 569
@@ -852,9 +866,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
852 del_timer(&sta->plink_timer); 866 del_timer(&sta->plink_timer);
853 sta->plink_state = NL80211_PLINK_ESTAB; 867 sta->plink_state = NL80211_PLINK_ESTAB;
854 spin_unlock_bh(&sta->lock); 868 spin_unlock_bh(&sta->lock);
855 mesh_plink_inc_estab_count(sdata); 869 changed |= mesh_plink_inc_estab_count(sdata);
856 changed |= mesh_set_ht_prot_mode(sdata); 870 changed |= mesh_set_ht_prot_mode(sdata);
857 changed |= BSS_CHANGED_BEACON;
858 mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", 871 mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
859 sta->sta.addr); 872 sta->sta.addr);
860 break; 873 break;
@@ -888,9 +901,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
888 del_timer(&sta->plink_timer); 901 del_timer(&sta->plink_timer);
889 sta->plink_state = NL80211_PLINK_ESTAB; 902 sta->plink_state = NL80211_PLINK_ESTAB;
890 spin_unlock_bh(&sta->lock); 903 spin_unlock_bh(&sta->lock);
891 mesh_plink_inc_estab_count(sdata); 904 changed |= mesh_plink_inc_estab_count(sdata);
892 changed |= mesh_set_ht_prot_mode(sdata); 905 changed |= mesh_set_ht_prot_mode(sdata);
893 changed |= BSS_CHANGED_BEACON;
894 mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", 906 mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
895 sta->sta.addr); 907 sta->sta.addr);
896 mesh_plink_frame_tx(sdata, 908 mesh_plink_frame_tx(sdata,
@@ -908,13 +920,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
908 case CLS_ACPT: 920 case CLS_ACPT:
909 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); 921 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
910 sta->reason = reason; 922 sta->reason = reason;
911 __mesh_plink_deactivate(sta); 923 changed |= __mesh_plink_deactivate(sta);
912 sta->plink_state = NL80211_PLINK_HOLDING; 924 sta->plink_state = NL80211_PLINK_HOLDING;
913 llid = sta->llid; 925 llid = sta->llid;
914 mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); 926 mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
915 spin_unlock_bh(&sta->lock); 927 spin_unlock_bh(&sta->lock);
916 changed |= mesh_set_ht_prot_mode(sdata); 928 changed |= mesh_set_ht_prot_mode(sdata);
917 changed |= BSS_CHANGED_BEACON;
918 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, 929 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
919 sta->sta.addr, llid, plid, reason); 930 sta->sta.addr, llid, plid, reason);
920 break; 931 break;