diff options
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r-- | net/mac80211/mesh_plink.c | 85 |
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 | ||
50 | static inline | 50 | static inline |
51 | void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | 51 | u32 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 | ||
57 | static inline | 57 | static inline |
58 | void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | 58 | u32 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 | */ |
176 | static bool __mesh_plink_deactivate(struct sta_info *sta) | 178 | static 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) | |||
198 | void mesh_plink_deactivate(struct sta_info *sta) | 198 | void 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 | ||
215 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 214 | static 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; |
327 | free: | ||
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) | |||
541 | void mesh_plink_block(struct sta_info *sta) | 556 | void 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; |