Blame view
net/mac80211/mesh_plink.c
32.2 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
c3896d2ca mac80211: mesh pe... |
2 |
/* |
264d9b7d8 mac80211: update ... |
3 |
* Copyright (c) 2008, 2009 open80211s Ltd. |
4abb52a46 mac80211: pass bs... |
4 |
* Copyright (C) 2019 Intel Corporation |
c3896d2ca mac80211: mesh pe... |
5 |
* Author: Luis Carlos Cobo <luisca@cozybit.com> |
c3896d2ca mac80211: mesh pe... |
6 |
*/ |
5a0e3ad6a include cleanup: ... |
7 |
#include <linux/gfp.h> |
902acc789 mac80211: clean u... |
8 9 |
#include <linux/kernel.h> #include <linux/random.h> |
b2d091031 sched/headers: Pr... |
10 |
#include <linux/rculist.h> |
c3896d2ca mac80211: mesh pe... |
11 |
#include "ieee80211_i.h" |
2c8dccc77 mac80211: rename ... |
12 |
#include "rate.h" |
c3896d2ca mac80211: mesh pe... |
13 |
#include "mesh.h" |
c3896d2ca mac80211: mesh pe... |
14 |
|
a69bd8e60 mac80211: mesh: s... |
15 |
#define PLINK_CNF_AID(mgmt) ((mgmt)->u.action.u.self_prot.variable + 2) |
8db098507 mac80211: update ... |
16 17 |
#define PLINK_GET_LLID(p) (p + 2) #define PLINK_GET_PLID(p) (p + 4) |
c3896d2ca mac80211: mesh pe... |
18 |
|
433f5bc1c mac80211: move me... |
19 |
#define mod_plink_timer(s, t) (mod_timer(&s->mesh->plink_timer, \ |
cc57ac536 mesh_plink: use m... |
20 |
jiffies + msecs_to_jiffies(t))) |
c3896d2ca mac80211: mesh pe... |
21 |
|
c3896d2ca mac80211: mesh pe... |
22 23 24 25 26 27 28 29 30 31 32 |
enum plink_event { PLINK_UNDEFINED, OPN_ACPT, OPN_RJCT, OPN_IGNR, CNF_ACPT, CNF_RJCT, CNF_IGNR, CLS_ACPT, CLS_IGNR }; |
95e48addb mac80211: stringi... |
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
static const char * const mplstates[] = { [NL80211_PLINK_LISTEN] = "LISTEN", [NL80211_PLINK_OPN_SNT] = "OPN-SNT", [NL80211_PLINK_OPN_RCVD] = "OPN-RCVD", [NL80211_PLINK_CNF_RCVD] = "CNF_RCVD", [NL80211_PLINK_ESTAB] = "ESTAB", [NL80211_PLINK_HOLDING] = "HOLDING", [NL80211_PLINK_BLOCKED] = "BLOCKED" }; static const char * const mplevents[] = { [PLINK_UNDEFINED] = "NONE", [OPN_ACPT] = "OPN_ACPT", [OPN_RJCT] = "OPN_RJCT", [OPN_IGNR] = "OPN_IGNR", [CNF_ACPT] = "CNF_ACPT", [CNF_RJCT] = "CNF_RJCT", [CNF_IGNR] = "CNF_IGNR", [CLS_ACPT] = "CLS_ACPT", [CLS_IGNR] = "CLS_IGNR" }; |
36c9bb29b mac80211: mesh: r... |
54 55 56 57 58 59 |
/* We only need a valid sta if user configured a minimum rssi_threshold. */ static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata, struct sta_info *sta) { s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold; return rssi_threshold == 0 || |
e5a9f8d04 mac80211: move st... |
60 |
(sta && |
0be6ed133 mac80211: move av... |
61 |
(s8)-ewma_signal_read(&sta->rx_stats_avg.signal) > |
e5a9f8d04 mac80211: move st... |
62 |
rssi_threshold); |
36c9bb29b mac80211: mesh: r... |
63 |
} |
c3896d2ca mac80211: mesh pe... |
64 65 66 |
/** * mesh_plink_fsm_restart - restart a mesh peer link finite state machine * |
23c7a29cd mac80211: fix typ... |
67 |
* @sta: mesh peer link to restart |
c3896d2ca mac80211: mesh pe... |
68 |
* |
433f5bc1c mac80211: move me... |
69 |
* Locking: this function must be called holding sta->mesh->plink_lock |
c3896d2ca mac80211: mesh pe... |
70 71 72 |
*/ static inline void mesh_plink_fsm_restart(struct sta_info *sta) { |
433f5bc1c mac80211: move me... |
73 74 75 76 |
lockdep_assert_held(&sta->mesh->plink_lock); sta->mesh->plink_state = NL80211_PLINK_LISTEN; sta->mesh->llid = sta->mesh->plid = sta->mesh->reason = 0; sta->mesh->plink_retries = 0; |
c3896d2ca mac80211: mesh pe... |
77 |
} |
3b144658b mac80211: dynamic... |
78 79 80 81 82 83 84 85 86 87 88 89 90 |
/* * mesh_set_short_slot_time - enable / disable ERP short slot time. * * The standard indirectly mandates mesh STAs to turn off short slot time by * disallowing advertising this (802.11-2012 8.4.1.4), but that doesn't mean we * can't be sneaky about it. Enable short slot time if all mesh STAs in the * MBSS support ERP rates. * * Returns BSS_CHANGED_ERP_SLOT or 0 for no change. */ static u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; |
21a8e9dd5 mac80211: Fix pos... |
91 |
struct ieee80211_supported_band *sband; |
3b144658b mac80211: dynamic... |
92 93 94 95 |
struct sta_info *sta; u32 erp_rates = 0, changed = 0; int i; bool short_slot = false; |
21a8e9dd5 mac80211: Fix pos... |
96 97 98 99 100 |
sband = ieee80211_get_sband(sdata); if (!sband) return changed; if (sband->band == NL80211_BAND_5GHZ) { |
3b144658b mac80211: dynamic... |
101 102 103 |
/* (IEEE 802.11-2012 19.4.5) */ short_slot = true; goto out; |
21a8e9dd5 mac80211: Fix pos... |
104 |
} else if (sband->band != NL80211_BAND_2GHZ) { |
3b144658b mac80211: dynamic... |
105 |
goto out; |
21a8e9dd5 mac80211: Fix pos... |
106 |
} |
3b144658b mac80211: dynamic... |
107 108 109 110 111 112 113 114 115 116 117 |
for (i = 0; i < sband->n_bitrates; i++) if (sband->bitrates[i].flags & IEEE80211_RATE_ERP_G) erp_rates |= BIT(i); if (!erp_rates) goto out; rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { if (sdata != sta->sdata || |
433f5bc1c mac80211: move me... |
118 |
sta->mesh->plink_state != NL80211_PLINK_ESTAB) |
3b144658b mac80211: dynamic... |
119 120 121 |
continue; short_slot = false; |
21a8e9dd5 mac80211: Fix pos... |
122 |
if (erp_rates & sta->sta.supp_rates[sband->band]) |
3b144658b mac80211: dynamic... |
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
short_slot = true; else break; } rcu_read_unlock(); out: if (sdata->vif.bss_conf.use_short_slot != short_slot) { sdata->vif.bss_conf.use_short_slot = short_slot; changed = BSS_CHANGED_ERP_SLOT; mpl_dbg(sdata, "mesh_plink %pM: ERP short slot time %d ", sdata->vif.addr, short_slot); } return changed; } |
2c53040f0 net: Fix (nearly-... |
139 |
/** |
cbf9322eb mac80211: Modify ... |
140 |
* mesh_set_ht_prot_mode - set correct HT protection mode |
21439b652 mac80211: fix som... |
141 |
* @sdata: the (mesh) interface to handle |
57aac7c51 mac80211: Impleme... |
142 |
* |
cbf9322eb mac80211: Modify ... |
143 144 145 146 147 148 |
* Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT * mesh STA in a MBSS. Three HT protection modes are supported for now, non-HT * mixed mode, 20MHz-protection and no-protection mode. non-HT mixed mode is * selected if any non-HT peers are present in our MBSS. 20MHz-protection mode * is selected if all peers in our 20/40MHz MBSS support HT and atleast one * HT20 peer is present. Otherwise no-protection mode is selected. |
57aac7c51 mac80211: Impleme... |
149 150 151 152 153 |
*/ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct sta_info *sta; |
57aac7c51 mac80211: Impleme... |
154 155 |
u16 ht_opmode; bool non_ht_sta = false, ht20_sta = false; |
0418a4458 mac80211: fix var... |
156 157 158 159 |
switch (sdata->vif.bss_conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: |
57aac7c51 mac80211: Impleme... |
160 |
return 0; |
0418a4458 mac80211: fix var... |
161 162 163 |
default: break; } |
57aac7c51 mac80211: Impleme... |
164 165 166 |
rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { |
cbf9322eb mac80211: Modify ... |
167 |
if (sdata != sta->sdata || |
433f5bc1c mac80211: move me... |
168 |
sta->mesh->plink_state != NL80211_PLINK_ESTAB) |
cbf9322eb mac80211: Modify ... |
169 |
continue; |
52ac8c488 mac80211: clean u... |
170 171 172 173 174 175 176 |
if (sta->sta.bandwidth > IEEE80211_STA_RX_BW_20) continue; if (!sta->sta.ht_cap.ht_supported) { mpl_dbg(sdata, "nonHT sta (%pM) is present ", sta->sta.addr); |
cbf9322eb mac80211: Modify ... |
177 |
non_ht_sta = true; |
cbf9322eb mac80211: Modify ... |
178 |
break; |
57aac7c51 mac80211: Impleme... |
179 |
} |
52ac8c488 mac80211: clean u... |
180 181 182 183 |
mpl_dbg(sdata, "HT20 sta (%pM) is present ", sta->sta.addr); ht20_sta = true; |
57aac7c51 mac80211: Impleme... |
184 |
} |
57aac7c51 mac80211: Impleme... |
185 186 187 188 |
rcu_read_unlock(); if (non_ht_sta) ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; |
466f310d1 mac80211: mesh: d... |
189 |
else if (ht20_sta && |
4bf88530b mac80211: convert... |
190 |
sdata->vif.bss_conf.chandef.width > NL80211_CHAN_WIDTH_20) |
57aac7c51 mac80211: Impleme... |
191 192 193 |
ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; else ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; |
52ac8c488 mac80211: clean u... |
194 195 |
if (sdata->vif.bss_conf.ht_operation_mode == ht_opmode) return 0; |
57aac7c51 mac80211: Impleme... |
196 |
|
52ac8c488 mac80211: clean u... |
197 198 199 200 201 |
sdata->vif.bss_conf.ht_operation_mode = ht_opmode; sdata->u.mesh.mshcfg.ht_opmode = ht_opmode; mpl_dbg(sdata, "selected new HT protection mode %d ", ht_opmode); return BSS_CHANGED_HT; |
57aac7c51 mac80211: Impleme... |
202 |
} |
f698d856f replace net_devic... |
203 |
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
a69bd8e60 mac80211: mesh: s... |
204 |
struct sta_info *sta, |
bf7cd94dc mac80211: clean u... |
205 |
enum ieee80211_self_protected_actioncode action, |
6f101ef04 mac80211: use put... |
206 |
u8 *da, u16 llid, u16 plid, u16 reason) |
bf7cd94dc mac80211: clean u... |
207 |
{ |
f698d856f replace net_devic... |
208 |
struct ieee80211_local *local = sdata->local; |
3b69a9c5f mac80211: comment... |
209 |
struct sk_buff *skb; |
e7570dfb6 mac80211: don't r... |
210 |
struct ieee80211_tx_info *info; |
c3896d2ca mac80211: mesh pe... |
211 212 |
struct ieee80211_mgmt *mgmt; bool include_plid = false; |
8db098507 mac80211: update ... |
213 |
u16 peering_proto = 0; |
3b69a9c5f mac80211: comment... |
214 |
u8 *pos, ie_len = 4; |
60ad72da5 mac80211: impleme... |
215 |
u8 ie_len_he_cap; |
4c121fd69 mac80211: use off... |
216 |
int hdr_len = offsetofend(struct ieee80211_mgmt, u.action.u.self_prot); |
f609a43dc mac80211: skb lea... |
217 |
int err = -ENOMEM; |
3b69a9c5f mac80211: comment... |
218 |
|
60ad72da5 mac80211: impleme... |
219 220 |
ie_len_he_cap = ieee80211_ie_len_he_cap(sdata, NL80211_IFTYPE_MESH_POINT); |
65e8b0ccb mac80211: Use the... |
221 |
skb = dev_alloc_skb(local->tx_headroom + |
3b69a9c5f mac80211: comment... |
222 223 224 225 226 227 228 |
hdr_len + 2 + /* capability info */ 2 + /* AID */ 2 + 8 + /* supported rates */ 2 + (IEEE80211_MAX_SUPP_RATES - 8) + 2 + sdata->u.mesh.mesh_id_len + 2 + sizeof(struct ieee80211_meshconf_ie) + |
176f36086 mac80211: add HT ... |
229 |
2 + sizeof(struct ieee80211_ht_cap) + |
074d46d1d wireless: rename ... |
230 |
2 + sizeof(struct ieee80211_ht_operation) + |
c85fb53c4 mac80211: impleme... |
231 232 |
2 + sizeof(struct ieee80211_vht_cap) + 2 + sizeof(struct ieee80211_vht_operation) + |
60ad72da5 mac80211: impleme... |
233 234 |
ie_len_he_cap + 2 + 1 + sizeof(struct ieee80211_he_operation) + |
d1b7524b3 mac80211: build H... |
235 |
sizeof(struct ieee80211_he_6ghz_oper) + |
24a2042cb mac80211: add HE ... |
236 |
2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) + |
3b69a9c5f mac80211: comment... |
237 238 |
2 + 8 + /* peering IE */ sdata->u.mesh.ie_len); |
c3896d2ca mac80211: mesh pe... |
239 |
if (!skb) |
87d84c452 mac80211: return ... |
240 |
return err; |
e7570dfb6 mac80211: don't r... |
241 |
info = IEEE80211_SKB_CB(skb); |
65e8b0ccb mac80211: Use the... |
242 |
skb_reserve(skb, local->tx_headroom); |
b080db585 networking: conve... |
243 |
mgmt = skb_put_zero(skb, hdr_len); |
e7827a703 mac80211: remove ... |
244 245 |
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); |
c3896d2ca mac80211: mesh pe... |
246 |
memcpy(mgmt->da, da, ETH_ALEN); |
47846c9b0 mac80211: reduce ... |
247 |
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
915b5c50f open80211s: Stop ... |
248 |
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); |
8db098507 mac80211: update ... |
249 250 |
mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED; mgmt->u.action.u.self_prot.action_code = action; |
c3896d2ca mac80211: mesh pe... |
251 |
|
8db098507 mac80211: update ... |
252 |
if (action != WLAN_SP_MESH_PEERING_CLOSE) { |
21a8e9dd5 mac80211: Fix pos... |
253 254 255 256 257 258 259 260 261 |
struct ieee80211_supported_band *sband; enum nl80211_band band; sband = ieee80211_get_sband(sdata); if (!sband) { err = -EINVAL; goto free; } band = sband->band; |
55de908ab mac80211: use cha... |
262 |
|
8db098507 mac80211: update ... |
263 |
/* capability info */ |
e45a79da8 skbuff/mac80211: ... |
264 |
pos = skb_put_zero(skb, 2); |
54ef656b0 mac80211: update ... |
265 |
if (action == WLAN_SP_MESH_PEERING_CONFIRM) { |
8db098507 mac80211: update ... |
266 267 |
/* AID */ pos = skb_put(skb, 2); |
a69bd8e60 mac80211: mesh: s... |
268 |
put_unaligned_le16(sta->sta.aid, pos); |
c3896d2ca mac80211: mesh pe... |
269 |
} |
55de908ab mac80211: use cha... |
270 271 |
if (ieee80211_add_srates_ie(sdata, skb, true, band) || ieee80211_add_ext_srates_ie(sdata, skb, true, band) || |
bf7cd94dc mac80211: clean u... |
272 273 274 |
mesh_add_rsn_ie(sdata, skb) || mesh_add_meshid_ie(sdata, skb) || mesh_add_meshconf_ie(sdata, skb)) |
f609a43dc mac80211: skb lea... |
275 |
goto free; |
8db098507 mac80211: update ... |
276 |
} else { /* WLAN_SP_MESH_PEERING_CLOSE */ |
e7570dfb6 mac80211: don't r... |
277 |
info->flags |= IEEE80211_TX_CTL_NO_ACK; |
bf7cd94dc mac80211: clean u... |
278 |
if (mesh_add_meshid_ie(sdata, skb)) |
f609a43dc mac80211: skb lea... |
279 |
goto free; |
c3896d2ca mac80211: mesh pe... |
280 |
} |
8db098507 mac80211: update ... |
281 |
/* Add Mesh Peering Management element */ |
c3896d2ca mac80211: mesh pe... |
282 |
switch (action) { |
54ef656b0 mac80211: update ... |
283 |
case WLAN_SP_MESH_PEERING_OPEN: |
c3896d2ca mac80211: mesh pe... |
284 |
break; |
54ef656b0 mac80211: update ... |
285 |
case WLAN_SP_MESH_PEERING_CONFIRM: |
8db098507 mac80211: update ... |
286 |
ie_len += 2; |
c3896d2ca mac80211: mesh pe... |
287 288 |
include_plid = true; break; |
54ef656b0 mac80211: update ... |
289 |
case WLAN_SP_MESH_PEERING_CLOSE: |
8db098507 mac80211: update ... |
290 291 |
if (plid) { ie_len += 2; |
c3896d2ca mac80211: mesh pe... |
292 293 |
include_plid = true; } |
8db098507 mac80211: update ... |
294 |
ie_len += 2; /* reason code */ |
c3896d2ca mac80211: mesh pe... |
295 |
break; |
8db098507 mac80211: update ... |
296 |
default: |
f609a43dc mac80211: skb lea... |
297 298 |
err = -EINVAL; goto free; |
c3896d2ca mac80211: mesh pe... |
299 |
} |
8db098507 mac80211: update ... |
300 |
if (WARN_ON(skb_tailroom(skb) < 2 + ie_len)) |
f609a43dc mac80211: skb lea... |
301 |
goto free; |
8db098507 mac80211: update ... |
302 |
|
c3896d2ca mac80211: mesh pe... |
303 |
pos = skb_put(skb, 2 + ie_len); |
8db098507 mac80211: update ... |
304 |
*pos++ = WLAN_EID_PEER_MGMT; |
c3896d2ca mac80211: mesh pe... |
305 |
*pos++ = ie_len; |
8db098507 mac80211: update ... |
306 307 |
memcpy(pos, &peering_proto, 2); pos += 2; |
6f101ef04 mac80211: use put... |
308 |
put_unaligned_le16(llid, pos); |
8db098507 mac80211: update ... |
309 |
pos += 2; |
c3896d2ca mac80211: mesh pe... |
310 |
if (include_plid) { |
6f101ef04 mac80211: use put... |
311 |
put_unaligned_le16(plid, pos); |
8db098507 mac80211: update ... |
312 |
pos += 2; |
c3896d2ca mac80211: mesh pe... |
313 |
} |
54ef656b0 mac80211: update ... |
314 |
if (action == WLAN_SP_MESH_PEERING_CLOSE) { |
6f101ef04 mac80211: use put... |
315 |
put_unaligned_le16(reason, pos); |
8db098507 mac80211: update ... |
316 |
pos += 2; |
c3896d2ca mac80211: mesh pe... |
317 |
} |
176f36086 mac80211: add HT ... |
318 319 |
if (action != WLAN_SP_MESH_PEERING_CLOSE) { |
bf7cd94dc mac80211: clean u... |
320 |
if (mesh_add_ht_cap_ie(sdata, skb) || |
c85fb53c4 mac80211: impleme... |
321 322 |
mesh_add_ht_oper_ie(sdata, skb) || mesh_add_vht_cap_ie(sdata, skb) || |
60ad72da5 mac80211: impleme... |
323 324 |
mesh_add_vht_oper_ie(sdata, skb) || mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) || |
24a2042cb mac80211: add HE ... |
325 326 |
mesh_add_he_oper_ie(sdata, skb) || mesh_add_he_6ghz_cap_ie(sdata, skb)) |
f609a43dc mac80211: skb lea... |
327 |
goto free; |
176f36086 mac80211: add HT ... |
328 |
} |
bf7cd94dc mac80211: clean u... |
329 |
if (mesh_add_vendor_ies(sdata, skb)) |
f609a43dc mac80211: skb lea... |
330 |
goto free; |
c3896d2ca mac80211: mesh pe... |
331 |
|
62ae67be3 mac80211: remove ... |
332 |
ieee80211_tx_skb(sdata, skb); |
c3896d2ca mac80211: mesh pe... |
333 |
return 0; |
f609a43dc mac80211: skb lea... |
334 335 336 |
free: kfree_skb(skb); return err; |
c3896d2ca mac80211: mesh pe... |
337 |
} |
fa87a6566 mac80211: reorder... |
338 339 340 341 342 |
/** * __mesh_plink_deactivate - deactivate mesh peer link * * @sta: mesh peer link to deactivate * |
e596af827 mac80211: mesh: f... |
343 344 345 |
* Mesh paths with this peer as next hop should be flushed * by the caller outside of plink_lock. * |
fa87a6566 mac80211: reorder... |
346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
* Returns beacon changed flag if the beacon content changed. * * Locking: the caller must hold sta->mesh->plink_lock */ static u32 __mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; u32 changed = 0; lockdep_assert_held(&sta->mesh->plink_lock); if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) changed = mesh_plink_dec_estab_count(sdata); sta->mesh->plink_state = NL80211_PLINK_BLOCKED; |
fa87a6566 mac80211: reorder... |
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
ieee80211_mps_sta_status_update(sta); changed |= ieee80211_mps_set_sta_local_pm(sta, NL80211_MESH_POWER_UNKNOWN); return changed; } /** * mesh_plink_deactivate - deactivate mesh peer link * * @sta: mesh peer link to deactivate * * All mesh paths with this peer as next hop will be flushed */ u32 mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; u32 changed; spin_lock_bh(&sta->mesh->plink_lock); changed = __mesh_plink_deactivate(sta); |
efc401f49 mac80211: use com... |
382 383 384 385 386 387 388 |
if (!sdata->u.mesh.user_mpm) { sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED; mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_CLOSE, sta->sta.addr, sta->mesh->llid, sta->mesh->plid, sta->mesh->reason); } |
fa87a6566 mac80211: reorder... |
389 |
spin_unlock_bh(&sta->mesh->plink_lock); |
efc401f49 mac80211: use com... |
390 391 |
if (!sdata->u.mesh.user_mpm) del_timer_sync(&sta->mesh->plink_timer); |
e596af827 mac80211: mesh: f... |
392 |
mesh_path_flush_by_nexthop(sta); |
fa87a6566 mac80211: reorder... |
393 |
|
efc401f49 mac80211: use com... |
394 395 |
/* make sure no readers can access nexthop sta from here on */ synchronize_net(); |
fa87a6566 mac80211: reorder... |
396 397 |
return changed; } |
296fcba3b mac80211: clean u... |
398 399 |
static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, |
1d6741d86 mac80211: mesh: f... |
400 |
struct ieee802_11_elems *elems) |
c3896d2ca mac80211: mesh pe... |
401 |
{ |
f698d856f replace net_devic... |
402 |
struct ieee80211_local *local = sdata->local; |
54ab1ffb6 mac80211: refacto... |
403 |
struct ieee80211_supported_band *sband; |
f68d776a0 mac80211: support... |
404 |
u32 rates, basic_rates = 0, changed = 0; |
abcff6ef0 mac80211: add VHT... |
405 |
enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth; |
c3896d2ca mac80211: mesh pe... |
406 |
|
21a8e9dd5 mac80211: Fix pos... |
407 408 409 410 411 412 |
sband = ieee80211_get_sband(sdata); if (!sband) return; rates = ieee80211_sta_get_rates(sdata, elems, sband->band, &basic_rates); |
d0709a651 mac80211: RCU-ify... |
413 |
|
433f5bc1c mac80211: move me... |
414 |
spin_lock_bh(&sta->mesh->plink_lock); |
e5a9f8d04 mac80211: move st... |
415 |
sta->rx_stats.last_rx = jiffies; |
296fcba3b mac80211: clean u... |
416 417 |
/* rates and capabilities don't change during peering */ |
433f5bc1c mac80211: move me... |
418 419 |
if (sta->mesh->plink_state == NL80211_PLINK_ESTAB && sta->mesh->processed_beacon) |
296fcba3b mac80211: clean u... |
420 |
goto out; |
433f5bc1c mac80211: move me... |
421 |
sta->mesh->processed_beacon = true; |
bae35d92b mac80211: don't r... |
422 |
|
21a8e9dd5 mac80211: Fix pos... |
423 |
if (sta->sta.supp_rates[sband->band] != rates) |
f68d776a0 mac80211: support... |
424 |
changed |= IEEE80211_RC_SUPP_RATES_CHANGED; |
21a8e9dd5 mac80211: Fix pos... |
425 |
sta->sta.supp_rates[sband->band] = rates; |
54ab1ffb6 mac80211: refacto... |
426 |
|
52ac8c488 mac80211: clean u... |
427 428 429 |
if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, sta)) changed |= IEEE80211_RC_BW_CHANGED; |
4bf88530b mac80211: convert... |
430 |
|
c85fb53c4 mac80211: impleme... |
431 432 |
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, elems->vht_cap_elem, sta); |
60ad72da5 mac80211: impleme... |
433 |
ieee80211_he_cap_ie_to_sta_he_cap(sdata, sband, elems->he_cap, |
1bb9a8a4c mac80211: use HE ... |
434 435 436 |
elems->he_cap_len, elems->he_6ghz_capa, sta); |
60ad72da5 mac80211: impleme... |
437 |
|
abcff6ef0 mac80211: add VHT... |
438 439 |
if (bw != sta->sta.bandwidth) changed |= IEEE80211_RC_BW_CHANGED; |
52ac8c488 mac80211: clean u... |
440 441 442 443 444 |
/* HT peer is operating 20MHz-only */ if (elems->ht_operation && !(elems->ht_operation->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { if (sta->sta.bandwidth != IEEE80211_STA_RX_BW_20) |
f68d776a0 mac80211: support... |
445 |
changed |= IEEE80211_RC_BW_CHANGED; |
52ac8c488 mac80211: clean u... |
446 |
sta->sta.bandwidth = IEEE80211_STA_RX_BW_20; |
57aac7c51 mac80211: Impleme... |
447 |
} |
c7d258288 mac80211: don't t... |
448 |
|
1d6741d86 mac80211: mesh: f... |
449 |
if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) |
59cf1d65f mac80211: don't r... |
450 |
rate_control_rate_init(sta); |
f68d776a0 mac80211: support... |
451 452 |
else rate_control_rate_update(local, sband, sta, changed); |
296fcba3b mac80211: clean u... |
453 |
out: |
433f5bc1c mac80211: move me... |
454 |
spin_unlock_bh(&sta->mesh->plink_lock); |
296fcba3b mac80211: clean u... |
455 |
} |
0e0060fcf mac80211: select ... |
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
static int mesh_allocate_aid(struct ieee80211_sub_if_data *sdata) { struct sta_info *sta; unsigned long *aid_map; int aid; aid_map = kcalloc(BITS_TO_LONGS(IEEE80211_MAX_AID + 1), sizeof(*aid_map), GFP_KERNEL); if (!aid_map) return -ENOMEM; /* reserve aid 0 for mcast indication */ __set_bit(0, aid_map); rcu_read_lock(); list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) __set_bit(sta->sta.aid, aid_map); rcu_read_unlock(); aid = find_first_zero_bit(aid_map, IEEE80211_MAX_AID + 1); kfree(aid_map); if (aid > IEEE80211_MAX_AID) return -ENOBUFS; return aid; } |
296fcba3b mac80211: clean u... |
483 484 485 486 |
static struct sta_info * __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) { struct sta_info *sta; |
0e0060fcf mac80211: select ... |
487 |
int aid; |
54ab1ffb6 mac80211: refacto... |
488 |
|
296fcba3b mac80211: clean u... |
489 |
if (sdata->local->num_sta >= MESH_MAX_PLINKS) |
e87278e73 mac80211: insert ... |
490 |
return NULL; |
0e0060fcf mac80211: select ... |
491 492 493 |
aid = mesh_allocate_aid(sdata); if (aid < 0) return NULL; |
296fcba3b mac80211: clean u... |
494 495 496 |
sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); if (!sta) return NULL; |
433f5bc1c mac80211: move me... |
497 |
sta->mesh->plink_state = NL80211_PLINK_LISTEN; |
a74a8c846 mac80211: don't d... |
498 |
sta->sta.wme = true; |
0e0060fcf mac80211: select ... |
499 |
sta->sta.aid = aid; |
296fcba3b mac80211: clean u... |
500 501 502 503 |
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED); |
296fcba3b mac80211: clean u... |
504 505 506 507 508 |
return sta; } static struct sta_info * mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr, |
ecbc12ad6 {nl,mac}80211: ad... |
509 510 |
struct ieee802_11_elems *elems, struct ieee80211_rx_status *rx_status) |
296fcba3b mac80211: clean u... |
511 512 |
{ struct sta_info *sta = NULL; |
a6dad6a26 mac80211: support... |
513 514 |
/* Userspace handles station allocation */ if (sdata->u.mesh.user_mpm || |
11197d006 mac80211: Suppres... |
515 516 |
sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { if (mesh_peer_accepts_plinks(elems) && |
ecbc12ad6 {nl,mac}80211: ad... |
517 518 519 520 521 |
mesh_plink_availables(sdata)) { int sig = 0; if (ieee80211_hw_check(&sdata->local->hw, SIGNAL_DBM)) sig = rx_status->signal; |
11197d006 mac80211: Suppres... |
522 523 524 |
cfg80211_notify_new_peer_candidate(sdata->dev, addr, elems->ie_start, elems->total_len, |
ecbc12ad6 {nl,mac}80211: ad... |
525 526 |
sig, GFP_KERNEL); } |
11197d006 mac80211: Suppres... |
527 |
} else |
296fcba3b mac80211: clean u... |
528 |
sta = __mesh_sta_info_alloc(sdata, addr); |
54ab1ffb6 mac80211: refacto... |
529 530 |
return sta; } |
296fcba3b mac80211: clean u... |
531 532 533 534 535 536 |
/* * mesh_sta_info_get - return mesh sta info entry for @addr. * * @sdata: local meshif * @addr: peer's address * @elems: IEs from beacon or mesh peering frame. |
ecbc12ad6 {nl,mac}80211: ad... |
537 |
* @rx_status: rx status for the frame for signal reporting |
296fcba3b mac80211: clean u... |
538 539 540 541 542 543 |
* * Return existing or newly allocated sta_info under RCU read lock. * (re)initialize with given IEs. */ static struct sta_info * mesh_sta_info_get(struct ieee80211_sub_if_data *sdata, |
ecbc12ad6 {nl,mac}80211: ad... |
544 545 |
u8 *addr, struct ieee802_11_elems *elems, struct ieee80211_rx_status *rx_status) __acquires(RCU) |
296fcba3b mac80211: clean u... |
546 547 548 549 550 551 |
{ struct sta_info *sta = NULL; rcu_read_lock(); sta = sta_info_get(sdata, addr); if (sta) { |
1d6741d86 mac80211: mesh: f... |
552 |
mesh_sta_info_init(sdata, sta, elems); |
296fcba3b mac80211: clean u... |
553 554 555 |
} else { rcu_read_unlock(); /* can't run atomic */ |
ecbc12ad6 {nl,mac}80211: ad... |
556 |
sta = mesh_sta_info_alloc(sdata, addr, elems, rx_status); |
296fcba3b mac80211: clean u... |
557 558 559 560 |
if (!sta) { rcu_read_lock(); return NULL; } |
1d6741d86 mac80211: mesh: f... |
561 |
mesh_sta_info_init(sdata, sta, elems); |
3b4797bce mac80211: fix mes... |
562 |
|
296fcba3b mac80211: clean u... |
563 564 565 566 567 568 569 570 571 572 573 574 575 |
if (sta_info_insert_rcu(sta)) return NULL; } return sta; } /* * mesh_neighbour_update - update or initialize new mesh neighbor. * * @sdata: local meshif * @addr: peer's address * @elems: IEs from beacon or mesh peering frame |
ecbc12ad6 {nl,mac}80211: ad... |
576 |
* @rx_status: rx status for the frame for signal reporting |
296fcba3b mac80211: clean u... |
577 578 579 |
* * Initiates peering if appropriate. */ |
f743ff490 mac80211: refacto... |
580 581 |
void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, u8 *hw_addr, |
ecbc12ad6 {nl,mac}80211: ad... |
582 583 |
struct ieee802_11_elems *elems, struct ieee80211_rx_status *rx_status) |
54ab1ffb6 mac80211: refacto... |
584 585 |
{ struct sta_info *sta; |
39886b618 mac80211: consoli... |
586 |
u32 changed = 0; |
54ab1ffb6 mac80211: refacto... |
587 |
|
ecbc12ad6 {nl,mac}80211: ad... |
588 |
sta = mesh_sta_info_get(sdata, hw_addr, elems, rx_status); |
54ab1ffb6 mac80211: refacto... |
589 590 |
if (!sta) goto out; |
dbdaee7aa {nl,mac}80211: re... |
591 592 |
sta->mesh->connected_to_gate = elems->mesh_config->meshconf_form & IEEE80211_MESHCONF_FORM_CONNECTED_TO_GATE; |
1570ca592 mac80211: send no... |
593 |
if (mesh_peer_accepts_plinks(elems) && |
433f5bc1c mac80211: move me... |
594 |
sta->mesh->plink_state == NL80211_PLINK_LISTEN && |
54ab1ffb6 mac80211: refacto... |
595 596 |
sdata->u.mesh.accepting_plinks && sdata->u.mesh.mshcfg.auto_open_plinks && |
36c9bb29b mac80211: mesh: r... |
597 |
rssi_threshold_check(sdata, sta)) |
39886b618 mac80211: consoli... |
598 |
changed = mesh_plink_open(sta); |
c3896d2ca mac80211: mesh pe... |
599 |
|
3f52b7e32 mac80211: mesh po... |
600 |
ieee80211_mps_frame_release(sta, elems); |
54ab1ffb6 mac80211: refacto... |
601 |
out: |
d0709a651 mac80211: RCU-ify... |
602 |
rcu_read_unlock(); |
2b5e19677 mac80211: cache m... |
603 |
ieee80211_mbss_info_change_notify(sdata, changed); |
c3896d2ca mac80211: mesh pe... |
604 |
} |
4c02d62fa net/mac80211/mesh... |
605 |
void mesh_plink_timer(struct timer_list *t) |
c3896d2ca mac80211: mesh pe... |
606 |
{ |
4c02d62fa net/mac80211/mesh... |
607 |
struct mesh_sta *mesh = from_timer(mesh, t, plink_timer); |
c3896d2ca mac80211: mesh pe... |
608 |
struct sta_info *sta; |
6f101ef04 mac80211: use put... |
609 |
u16 reason = 0; |
c3896d2ca mac80211: mesh pe... |
610 |
struct ieee80211_sub_if_data *sdata; |
453e66f24 mac80211: remove ... |
611 |
struct mesh_config *mshcfg; |
4efec4513 mac80211: consoli... |
612 |
enum ieee80211_self_protected_actioncode action = 0; |
c3896d2ca mac80211: mesh pe... |
613 |
|
d0709a651 mac80211: RCU-ify... |
614 615 616 617 618 |
/* * This STA is valid because sta_info_destroy() will * del_timer_sync() this timer after having made sure * it cannot be readded (by deleting the plink.) */ |
4c02d62fa net/mac80211/mesh... |
619 |
sta = mesh->plink_sta; |
c3896d2ca mac80211: mesh pe... |
620 |
|
690205f18 mac80211: cleanup... |
621 |
if (sta->sdata->local->quiescing) |
5bb644a0f mac80211: cancel/... |
622 |
return; |
5bb644a0f mac80211: cancel/... |
623 |
|
433f5bc1c mac80211: move me... |
624 |
spin_lock_bh(&sta->mesh->plink_lock); |
2b470c39e mac80211: remove ... |
625 626 627 628 629 630 |
/* If a timer fires just before a state transition on another CPU, * we may have already extended the timeout and changed state by the * time we've acquired the lock and arrived here. In that case, * skip this timer and wait for the new one. */ |
433f5bc1c mac80211: move me... |
631 |
if (time_before(jiffies, sta->mesh->plink_timer.expires)) { |
2b470c39e mac80211: remove ... |
632 633 |
mpl_dbg(sta->sdata, "Ignoring timer for %pM in state %s (timer adjusted)", |
433f5bc1c mac80211: move me... |
634 635 |
sta->sta.addr, mplstates[sta->mesh->plink_state]); spin_unlock_bh(&sta->mesh->plink_lock); |
c3896d2ca mac80211: mesh pe... |
636 637 |
return; } |
2b470c39e mac80211: remove ... |
638 639 |
/* del_timer() and handler may race when entering these states */ |
433f5bc1c mac80211: move me... |
640 641 |
if (sta->mesh->plink_state == NL80211_PLINK_LISTEN || sta->mesh->plink_state == NL80211_PLINK_ESTAB) { |
2b470c39e mac80211: remove ... |
642 643 |
mpl_dbg(sta->sdata, "Ignoring timer for %pM in state %s (timer deleted)", |
433f5bc1c mac80211: move me... |
644 645 |
sta->sta.addr, mplstates[sta->mesh->plink_state]); spin_unlock_bh(&sta->mesh->plink_lock); |
2b470c39e mac80211: remove ... |
646 647 |
return; } |
bdcbd8e0e mac80211: clean u... |
648 |
mpl_dbg(sta->sdata, |
3088f7d2d mac80211: stringi... |
649 650 |
"Mesh plink timer for %pM fired on state %s ", |
433f5bc1c mac80211: move me... |
651 |
sta->sta.addr, mplstates[sta->mesh->plink_state]); |
d0709a651 mac80211: RCU-ify... |
652 |
sdata = sta->sdata; |
453e66f24 mac80211: remove ... |
653 |
mshcfg = &sdata->u.mesh.mshcfg; |
c3896d2ca mac80211: mesh pe... |
654 |
|
433f5bc1c mac80211: move me... |
655 |
switch (sta->mesh->plink_state) { |
57cf8043a nl80211: Move pee... |
656 657 |
case NL80211_PLINK_OPN_RCVD: case NL80211_PLINK_OPN_SNT: |
c3896d2ca mac80211: mesh pe... |
658 |
/* retry timer */ |
433f5bc1c mac80211: move me... |
659 |
if (sta->mesh->plink_retries < mshcfg->dot11MeshMaxRetries) { |
c3896d2ca mac80211: mesh pe... |
660 |
u32 rand; |
bdcbd8e0e mac80211: clean u... |
661 662 663 |
mpl_dbg(sta->sdata, "Mesh plink for %pM (retry, timeout): %d %d ", |
433f5bc1c mac80211: move me... |
664 665 |
sta->sta.addr, sta->mesh->plink_retries, sta->mesh->plink_timeout); |
c3896d2ca mac80211: mesh pe... |
666 |
get_random_bytes(&rand, sizeof(u32)); |
433f5bc1c mac80211: move me... |
667 668 669 670 |
sta->mesh->plink_timeout = sta->mesh->plink_timeout + rand % sta->mesh->plink_timeout; ++sta->mesh->plink_retries; mod_plink_timer(sta, sta->mesh->plink_timeout); |
4efec4513 mac80211: consoli... |
671 |
action = WLAN_SP_MESH_PEERING_OPEN; |
c3896d2ca mac80211: mesh pe... |
672 673 |
break; } |
6f101ef04 mac80211: use put... |
674 |
reason = WLAN_REASON_MESH_MAX_RETRIES; |
fc0561dc6 mac80211: Use fal... |
675 |
fallthrough; |
57cf8043a nl80211: Move pee... |
676 |
case NL80211_PLINK_CNF_RCVD: |
c3896d2ca mac80211: mesh pe... |
677 678 |
/* confirm timer */ if (!reason) |
6f101ef04 mac80211: use put... |
679 |
reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT; |
433f5bc1c mac80211: move me... |
680 |
sta->mesh->plink_state = NL80211_PLINK_HOLDING; |
453e66f24 mac80211: remove ... |
681 |
mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
4efec4513 mac80211: consoli... |
682 |
action = WLAN_SP_MESH_PEERING_CLOSE; |
c3896d2ca mac80211: mesh pe... |
683 |
break; |
57cf8043a nl80211: Move pee... |
684 |
case NL80211_PLINK_HOLDING: |
c3896d2ca mac80211: mesh pe... |
685 |
/* holding timer */ |
433f5bc1c mac80211: move me... |
686 |
del_timer(&sta->mesh->plink_timer); |
c3896d2ca mac80211: mesh pe... |
687 |
mesh_plink_fsm_restart(sta); |
c3896d2ca mac80211: mesh pe... |
688 689 |
break; default: |
c3896d2ca mac80211: mesh pe... |
690 691 |
break; } |
433f5bc1c mac80211: move me... |
692 |
spin_unlock_bh(&sta->mesh->plink_lock); |
4efec4513 mac80211: consoli... |
693 |
if (action) |
a69bd8e60 mac80211: mesh: s... |
694 |
mesh_plink_frame_tx(sdata, sta, action, sta->sta.addr, |
433f5bc1c mac80211: move me... |
695 |
sta->mesh->llid, sta->mesh->plid, reason); |
c3896d2ca mac80211: mesh pe... |
696 |
} |
0df2f6c11 mesh_plink: fixup... |
697 |
static inline void mesh_plink_timer_set(struct sta_info *sta, u32 timeout) |
c3896d2ca mac80211: mesh pe... |
698 |
{ |
433f5bc1c mac80211: move me... |
699 |
sta->mesh->plink_timeout = timeout; |
4c02d62fa net/mac80211/mesh... |
700 |
mod_timer(&sta->mesh->plink_timer, jiffies + msecs_to_jiffies(timeout)); |
c3896d2ca mac80211: mesh pe... |
701 |
} |
204d13042 mac80211: clean u... |
702 |
static bool llid_in_use(struct ieee80211_sub_if_data *sdata, |
6f101ef04 mac80211: use put... |
703 |
u16 llid) |
204d13042 mac80211: clean u... |
704 705 706 707 708 709 710 |
{ struct ieee80211_local *local = sdata->local; bool in_use = false; struct sta_info *sta; rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { |
520c75dca mac80211: fix cra... |
711 712 |
if (sdata != sta->sdata) continue; |
433f5bc1c mac80211: move me... |
713 |
if (!memcmp(&sta->mesh->llid, &llid, sizeof(llid))) { |
204d13042 mac80211: clean u... |
714 715 716 717 718 719 720 721 |
in_use = true; break; } } rcu_read_unlock(); return in_use; } |
6f101ef04 mac80211: use put... |
722 |
static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) |
204d13042 mac80211: clean u... |
723 724 725 726 727 |
{ u16 llid; do { get_random_bytes(&llid, sizeof(llid)); |
6f101ef04 mac80211: use put... |
728 |
} while (llid_in_use(sdata, llid)); |
204d13042 mac80211: clean u... |
729 |
|
6f101ef04 mac80211: use put... |
730 |
return llid; |
204d13042 mac80211: clean u... |
731 |
} |
39886b618 mac80211: consoli... |
732 |
u32 mesh_plink_open(struct sta_info *sta) |
c3896d2ca mac80211: mesh pe... |
733 |
{ |
d0709a651 mac80211: RCU-ify... |
734 |
struct ieee80211_sub_if_data *sdata = sta->sdata; |
39886b618 mac80211: consoli... |
735 |
u32 changed; |
c3896d2ca mac80211: mesh pe... |
736 |
|
c2c98fdeb mac80211: optimis... |
737 |
if (!test_sta_flag(sta, WLAN_STA_AUTH)) |
39886b618 mac80211: consoli... |
738 |
return 0; |
53e805111 mac80211: ignore ... |
739 |
|
433f5bc1c mac80211: move me... |
740 741 742 743 744 |
spin_lock_bh(&sta->mesh->plink_lock); sta->mesh->llid = mesh_get_new_llid(sdata); if (sta->mesh->plink_state != NL80211_PLINK_LISTEN && sta->mesh->plink_state != NL80211_PLINK_BLOCKED) { spin_unlock_bh(&sta->mesh->plink_lock); |
39886b618 mac80211: consoli... |
745 |
return 0; |
c3896d2ca mac80211: mesh pe... |
746 |
} |
433f5bc1c mac80211: move me... |
747 |
sta->mesh->plink_state = NL80211_PLINK_OPN_SNT; |
453e66f24 mac80211: remove ... |
748 |
mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); |
433f5bc1c mac80211: move me... |
749 |
spin_unlock_bh(&sta->mesh->plink_lock); |
bdcbd8e0e mac80211: clean u... |
750 751 752 |
mpl_dbg(sdata, "Mesh plink: starting establishment with %pM ", |
0c68ae260 mac80211: convert... |
753 |
sta->sta.addr); |
c3896d2ca mac80211: mesh pe... |
754 |
|
3f52b7e32 mac80211: mesh po... |
755 |
/* set the non-peer mode to active during peering */ |
39886b618 mac80211: consoli... |
756 |
changed = ieee80211_mps_local_status_update(sdata); |
3f52b7e32 mac80211: mesh po... |
757 |
|
a69bd8e60 mac80211: mesh: s... |
758 |
mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_OPEN, |
433f5bc1c mac80211: move me... |
759 |
sta->sta.addr, sta->mesh->llid, 0, 0); |
39886b618 mac80211: consoli... |
760 |
return changed; |
c3896d2ca mac80211: mesh pe... |
761 |
} |
39886b618 mac80211: consoli... |
762 |
u32 mesh_plink_block(struct sta_info *sta) |
c3896d2ca mac80211: mesh pe... |
763 |
{ |
df3238189 mac80211: fix unn... |
764 |
u32 changed; |
c93701976 mac80211: avoid s... |
765 |
|
433f5bc1c mac80211: move me... |
766 |
spin_lock_bh(&sta->mesh->plink_lock); |
df3238189 mac80211: fix unn... |
767 |
changed = __mesh_plink_deactivate(sta); |
433f5bc1c mac80211: move me... |
768 769 |
sta->mesh->plink_state = NL80211_PLINK_BLOCKED; spin_unlock_bh(&sta->mesh->plink_lock); |
e596af827 mac80211: mesh: f... |
770 |
mesh_path_flush_by_nexthop(sta); |
c93701976 mac80211: avoid s... |
771 |
|
39886b618 mac80211: consoli... |
772 |
return changed; |
c3896d2ca mac80211: mesh pe... |
773 |
} |
e76d67f03 mac80211: mesh: f... |
774 775 776 777 778 |
static void mesh_plink_close(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, enum plink_event event) { struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; |
6f101ef04 mac80211: use put... |
779 780 |
u16 reason = (event == CLS_ACPT) ? WLAN_REASON_MESH_CLOSE : WLAN_REASON_MESH_CONFIG; |
e76d67f03 mac80211: mesh: f... |
781 |
|
433f5bc1c mac80211: move me... |
782 783 |
sta->mesh->reason = reason; sta->mesh->plink_state = NL80211_PLINK_HOLDING; |
272a9e261 mac80211: mesh_pl... |
784 |
mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); |
e76d67f03 mac80211: mesh: f... |
785 786 787 788 789 790 791 |
} static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, struct sta_info *sta) { struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; u32 changed = 0; |
433f5bc1c mac80211: move me... |
792 793 |
del_timer(&sta->mesh->plink_timer); sta->mesh->plink_state = NL80211_PLINK_ESTAB; |
e76d67f03 mac80211: mesh: f... |
794 795 796 797 798 799 800 801 802 |
changed |= mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); changed |= mesh_set_short_slot_time(sdata); mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED ", sta->sta.addr); ieee80211_mps_sta_status_update(sta); changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode); return changed; } |
c7e678115 mac80211: factor ... |
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 |
/** * mesh_plink_fsm - step @sta MPM based on @event * * @sdata: interface * @sta: mesh neighbor * @event: peering event * * Return: changed MBSS flags */ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, enum plink_event event) { struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; enum ieee80211_self_protected_actioncode action = 0; u32 changed = 0; |
e596af827 mac80211: mesh: f... |
818 |
bool flush = false; |
c7e678115 mac80211: factor ... |
819 820 821 |
mpl_dbg(sdata, "peer %pM in state %s got event %s ", sta->sta.addr, |
433f5bc1c mac80211: move me... |
822 |
mplstates[sta->mesh->plink_state], mplevents[event]); |
c7e678115 mac80211: factor ... |
823 |
|
433f5bc1c mac80211: move me... |
824 825 |
spin_lock_bh(&sta->mesh->plink_lock); switch (sta->mesh->plink_state) { |
c7e678115 mac80211: factor ... |
826 827 828 829 830 831 |
case NL80211_PLINK_LISTEN: switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); break; case OPN_ACPT: |
433f5bc1c mac80211: move me... |
832 833 |
sta->mesh->plink_state = NL80211_PLINK_OPN_RCVD; sta->mesh->llid = mesh_get_new_llid(sdata); |
c7e678115 mac80211: factor ... |
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 |
mesh_plink_timer_set(sta, mshcfg->dot11MeshRetryTimeout); /* set the non-peer mode to active during peering */ changed |= ieee80211_mps_local_status_update(sdata); action = WLAN_SP_MESH_PEERING_OPEN; break; default: break; } break; case NL80211_PLINK_OPN_SNT: switch (event) { case OPN_RJCT: case CNF_RJCT: case CLS_ACPT: mesh_plink_close(sdata, sta, event); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: /* retry timer is left untouched */ |
433f5bc1c mac80211: move me... |
855 |
sta->mesh->plink_state = NL80211_PLINK_OPN_RCVD; |
c7e678115 mac80211: factor ... |
856 857 858 |
action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: |
433f5bc1c mac80211: move me... |
859 |
sta->mesh->plink_state = NL80211_PLINK_CNF_RCVD; |
2b470c39e mac80211: remove ... |
860 |
mod_plink_timer(sta, mshcfg->dot11MeshConfirmTimeout); |
c7e678115 mac80211: factor ... |
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 |
break; default: break; } break; case NL80211_PLINK_OPN_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: case CLS_ACPT: mesh_plink_close(sdata, sta, event); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: changed |= mesh_plink_establish(sdata, sta); break; default: break; } break; case NL80211_PLINK_CNF_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: case CLS_ACPT: mesh_plink_close(sdata, sta, event); action = WLAN_SP_MESH_PEERING_CLOSE; break; case OPN_ACPT: changed |= mesh_plink_establish(sdata, sta); action = WLAN_SP_MESH_PEERING_CONFIRM; break; default: break; } break; case NL80211_PLINK_ESTAB: switch (event) { case CLS_ACPT: changed |= __mesh_plink_deactivate(sta); changed |= mesh_set_ht_prot_mode(sdata); changed |= mesh_set_short_slot_time(sdata); mesh_plink_close(sdata, sta, event); action = WLAN_SP_MESH_PEERING_CLOSE; |
e596af827 mac80211: mesh: f... |
908 |
flush = true; |
c7e678115 mac80211: factor ... |
909 910 911 912 913 914 915 916 917 918 919 |
break; case OPN_ACPT: action = WLAN_SP_MESH_PEERING_CONFIRM; break; default: break; } break; case NL80211_PLINK_HOLDING: switch (event) { case CLS_ACPT: |
433f5bc1c mac80211: move me... |
920 |
del_timer(&sta->mesh->plink_timer); |
c7e678115 mac80211: factor ... |
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 |
mesh_plink_fsm_restart(sta); break; case OPN_ACPT: case CNF_ACPT: case OPN_RJCT: case CNF_RJCT: action = WLAN_SP_MESH_PEERING_CLOSE; break; default: break; } break; default: /* should not get here, PLINK_BLOCKED is dealt with at the * beginning of the function */ break; } |
433f5bc1c mac80211: move me... |
939 |
spin_unlock_bh(&sta->mesh->plink_lock); |
e596af827 mac80211: mesh: f... |
940 941 |
if (flush) mesh_path_flush_by_nexthop(sta); |
c7e678115 mac80211: factor ... |
942 |
if (action) { |
a69bd8e60 mac80211: mesh: s... |
943 |
mesh_plink_frame_tx(sdata, sta, action, sta->sta.addr, |
433f5bc1c mac80211: move me... |
944 945 |
sta->mesh->llid, sta->mesh->plid, sta->mesh->reason); |
c7e678115 mac80211: factor ... |
946 947 948 |
/* also send confirm in open case */ if (action == WLAN_SP_MESH_PEERING_OPEN) { |
a69bd8e60 mac80211: mesh: s... |
949 |
mesh_plink_frame_tx(sdata, sta, |
c7e678115 mac80211: factor ... |
950 |
WLAN_SP_MESH_PEERING_CONFIRM, |
433f5bc1c mac80211: move me... |
951 952 |
sta->sta.addr, sta->mesh->llid, sta->mesh->plid, 0); |
c7e678115 mac80211: factor ... |
953 954 955 956 957 |
} } return changed; } |
c99a89edb mac80211: factor ... |
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 |
/* * mesh_plink_get_event - get correct MPM event * * @sdata: interface * @sta: peer, leave NULL if processing a frame from a new suitable peer * @elems: peering management IEs * @ftype: frame type * @llid: peer's peer link ID * @plid: peer's local link ID * * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as * an error. */ static enum plink_event mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee802_11_elems *elems, enum ieee80211_self_protected_actioncode ftype, |
6f101ef04 mac80211: use put... |
976 |
u16 llid, u16 plid) |
c99a89edb mac80211: factor ... |
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 |
{ enum plink_event event = PLINK_UNDEFINED; u8 ie_len = elems->peering_len; bool matches_local; matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE || mesh_matches_local(sdata, elems)); /* deny open request from non-matching peer */ if (!matches_local && !sta) { event = OPN_RJCT; goto out; } if (!sta) { if (ftype != WLAN_SP_MESH_PEERING_OPEN) { mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer "); goto out; } /* ftype == WLAN_SP_MESH_PEERING_OPEN */ if (!mesh_plink_free_count(sdata)) { mpl_dbg(sdata, "Mesh plink error: no more free plinks "); goto out; } |
b8631c003 mac80211: mesh_pl... |
1003 1004 1005 1006 |
/* new matching peer */ event = OPN_ACPT; goto out; |
c99a89edb mac80211: factor ... |
1007 1008 1009 1010 1011 1012 |
} else { if (!test_sta_flag(sta, WLAN_STA_AUTH)) { mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer "); goto out; } |
433f5bc1c mac80211: move me... |
1013 |
if (sta->mesh->plink_state == NL80211_PLINK_BLOCKED) |
c99a89edb mac80211: factor ... |
1014 1015 |
goto out; } |
c99a89edb mac80211: factor ... |
1016 1017 1018 1019 1020 |
switch (ftype) { case WLAN_SP_MESH_PEERING_OPEN: if (!matches_local) event = OPN_RJCT; if (!mesh_plink_free_count(sdata) || |
433f5bc1c mac80211: move me... |
1021 |
(sta->mesh->plid && sta->mesh->plid != plid)) |
c99a89edb mac80211: factor ... |
1022 1023 1024 1025 1026 1027 1028 1029 |
event = OPN_IGNR; else event = OPN_ACPT; break; case WLAN_SP_MESH_PEERING_CONFIRM: if (!matches_local) event = CNF_RJCT; if (!mesh_plink_free_count(sdata) || |
433f5bc1c mac80211: move me... |
1030 1031 |
sta->mesh->llid != llid || (sta->mesh->plid && sta->mesh->plid != plid)) |
c99a89edb mac80211: factor ... |
1032 1033 1034 1035 1036 |
event = CNF_IGNR; else event = CNF_ACPT; break; case WLAN_SP_MESH_PEERING_CLOSE: |
433f5bc1c mac80211: move me... |
1037 |
if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) |
c99a89edb mac80211: factor ... |
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
/* Do not check for llid or plid. This does not * follow the standard but since multiple plinks * per sta are not supported, it is necessary in * order to avoid a livelock when MP A sees an * establish peer link to MP B but MP B does not * see it. This can be caused by a timeout in * B's peer link establishment or B beign * restarted. */ event = CLS_ACPT; |
433f5bc1c mac80211: move me... |
1048 |
else if (sta->mesh->plid != plid) |
c99a89edb mac80211: factor ... |
1049 |
event = CLS_IGNR; |
433f5bc1c mac80211: move me... |
1050 |
else if (ie_len == 8 && sta->mesh->llid != llid) |
c99a89edb mac80211: factor ... |
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 |
event = CLS_IGNR; else event = CLS_ACPT; break; default: mpl_dbg(sdata, "Mesh plink: unknown frame subtype "); break; } out: return event; } |
05a23ae92 mac80211: factor ... |
1064 1065 1066 |
static void mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, |
ecbc12ad6 {nl,mac}80211: ad... |
1067 1068 |
struct ieee802_11_elems *elems, struct ieee80211_rx_status *rx_status) |
c3896d2ca mac80211: mesh pe... |
1069 |
{ |
05a23ae92 mac80211: factor ... |
1070 |
|
c3896d2ca mac80211: mesh pe... |
1071 1072 |
struct sta_info *sta; enum plink_event event; |
54ef656b0 mac80211: update ... |
1073 |
enum ieee80211_self_protected_actioncode ftype; |
57aac7c51 mac80211: Impleme... |
1074 |
u32 changed = 0; |
c99a89edb mac80211: factor ... |
1075 |
u8 ie_len = elems->peering_len; |
6f101ef04 mac80211: use put... |
1076 |
u16 plid, llid = 0; |
c3896d2ca mac80211: mesh pe... |
1077 |
|
05a23ae92 mac80211: factor ... |
1078 |
if (!elems->peering) { |
bdcbd8e0e mac80211: clean u... |
1079 1080 1081 |
mpl_dbg(sdata, "Mesh plink: missing necessary peer link ie "); |
c3896d2ca mac80211: mesh pe... |
1082 1083 |
return; } |
bf7cd94dc mac80211: clean u... |
1084 |
|
05a23ae92 mac80211: factor ... |
1085 |
if (elems->rsn_len && |
bf7cd94dc mac80211: clean u... |
1086 |
sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { |
bdcbd8e0e mac80211: clean u... |
1087 1088 1089 |
mpl_dbg(sdata, "Mesh plink: can't establish link with secure peer "); |
5cff5e01e mac80211: ignore ... |
1090 1091 |
return; } |
c3896d2ca mac80211: mesh pe... |
1092 |
|
8db098507 mac80211: update ... |
1093 |
ftype = mgmt->u.action.u.self_prot.action_code; |
8db098507 mac80211: update ... |
1094 1095 1096 1097 |
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) || (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 && ie_len != 8)) { |
bdcbd8e0e mac80211: clean u... |
1098 1099 1100 1101 |
mpl_dbg(sdata, "Mesh plink: incorrect plink ie length %d %d ", ftype, ie_len); |
c3896d2ca mac80211: mesh pe... |
1102 1103 |
return; } |
54ef656b0 mac80211: update ... |
1104 |
if (ftype != WLAN_SP_MESH_PEERING_CLOSE && |
05a23ae92 mac80211: factor ... |
1105 |
(!elems->mesh_id || !elems->mesh_config)) { |
bdcbd8e0e mac80211: clean u... |
1106 1107 |
mpl_dbg(sdata, "Mesh plink: missing necessary ie "); |
c3896d2ca mac80211: mesh pe... |
1108 1109 1110 1111 1112 |
return; } /* Note the lines below are correct, the llid in the frame is the plid * from the point of view of this host. */ |
f8134fed8 mac80211: mesh_pl... |
1113 |
plid = get_unaligned_le16(PLINK_GET_LLID(elems->peering)); |
54ef656b0 mac80211: update ... |
1114 |
if (ftype == WLAN_SP_MESH_PEERING_CONFIRM || |
f8134fed8 mac80211: mesh_pl... |
1115 1116 |
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) llid = get_unaligned_le16(PLINK_GET_PLID(elems->peering)); |
c3896d2ca mac80211: mesh pe... |
1117 |
|
296fcba3b mac80211: clean u... |
1118 |
/* WARNING: Only for sta pointer, is dropped & re-acquired */ |
d0709a651 mac80211: RCU-ify... |
1119 |
rcu_read_lock(); |
abe60632f mac80211: make st... |
1120 |
sta = sta_info_get(sdata, mgmt->sa); |
32cb05bfe mac80211: mesh_pl... |
1121 |
|
553351378 {nl,cfg,mac}80211... |
1122 |
if (ftype == WLAN_SP_MESH_PEERING_OPEN && |
36c9bb29b mac80211: mesh: r... |
1123 |
!rssi_threshold_check(sdata, sta)) { |
bdcbd8e0e mac80211: clean u... |
1124 1125 |
mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold ", |
3d4f96997 mac80211: Fix pot... |
1126 |
mgmt->sa); |
fc10302ef mac80211: consoli... |
1127 |
goto unlock_rcu; |
553351378 {nl,cfg,mac}80211... |
1128 |
} |
c3896d2ca mac80211: mesh pe... |
1129 |
/* Now we will figure out the appropriate event... */ |
c99a89edb mac80211: factor ... |
1130 |
event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid); |
54ab1ffb6 mac80211: refacto... |
1131 1132 |
if (event == OPN_ACPT) { |
296fcba3b mac80211: clean u... |
1133 |
rcu_read_unlock(); |
54ab1ffb6 mac80211: refacto... |
1134 |
/* allocate sta entry if necessary and update info */ |
ecbc12ad6 {nl,mac}80211: ad... |
1135 |
sta = mesh_sta_info_get(sdata, mgmt->sa, elems, rx_status); |
54ab1ffb6 mac80211: refacto... |
1136 |
if (!sta) { |
bdcbd8e0e mac80211: clean u... |
1137 1138 |
mpl_dbg(sdata, "Mesh plink: failed to init peer! "); |
fc10302ef mac80211: consoli... |
1139 |
goto unlock_rcu; |
54ab1ffb6 mac80211: refacto... |
1140 |
} |
433f5bc1c mac80211: move me... |
1141 |
sta->mesh->plid = plid; |
c99a89edb mac80211: factor ... |
1142 |
} else if (!sta && event == OPN_RJCT) { |
a69bd8e60 mac80211: mesh: s... |
1143 |
mesh_plink_frame_tx(sdata, NULL, WLAN_SP_MESH_PEERING_CLOSE, |
c99a89edb mac80211: factor ... |
1144 |
mgmt->sa, 0, plid, |
6f101ef04 mac80211: use put... |
1145 |
WLAN_REASON_MESH_CONFIG); |
c99a89edb mac80211: factor ... |
1146 1147 1148 1149 |
goto unlock_rcu; } else if (!sta || event == PLINK_UNDEFINED) { /* something went wrong */ goto unlock_rcu; |
c3896d2ca mac80211: mesh pe... |
1150 |
} |
a69bd8e60 mac80211: mesh: s... |
1151 1152 |
if (event == CNF_ACPT) { /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */ |
0e0060fcf mac80211: select ... |
1153 |
if (!sta->mesh->plid) |
a69bd8e60 mac80211: mesh: s... |
1154 |
sta->mesh->plid = plid; |
a69bd8e60 mac80211: mesh: s... |
1155 1156 1157 |
sta->mesh->aid = get_unaligned_le16(PLINK_CNF_AID(mgmt)); } |
6c6fa4964 mac80211: mesh_pl... |
1158 |
|
c7e678115 mac80211: factor ... |
1159 |
changed |= mesh_plink_fsm(sdata, sta, event); |
d0709a651 mac80211: RCU-ify... |
1160 |
|
fc10302ef mac80211: consoli... |
1161 |
unlock_rcu: |
d0709a651 mac80211: RCU-ify... |
1162 |
rcu_read_unlock(); |
57aac7c51 mac80211: Impleme... |
1163 |
|
ecccd072b mac80211: fix mes... |
1164 |
if (changed) |
2b5e19677 mac80211: cache m... |
1165 |
ieee80211_mbss_info_change_notify(sdata, changed); |
c3896d2ca mac80211: mesh pe... |
1166 |
} |
05a23ae92 mac80211: factor ... |
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 |
void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { struct ieee802_11_elems elems; size_t baselen; u8 *baseaddr; /* need action_code, aux */ if (len < IEEE80211_MIN_ACTION_SIZE + 3) return; if (sdata->u.mesh.user_mpm) /* userspace must register for these */ return; if (is_multicast_ether_addr(mgmt->da)) { mpl_dbg(sdata, "Mesh plink: ignore frame from multicast address "); return; } baseaddr = mgmt->u.action.u.self_prot.variable; baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt; if (mgmt->u.action.u.self_prot.action_code == WLAN_SP_MESH_PEERING_CONFIRM) { baseaddr += 4; baselen += 4; |
b3e7de873 mac80211: add mis... |
1197 1198 1199 |
if (baselen > len) return; |
05a23ae92 mac80211: factor ... |
1200 |
} |
4abb52a46 mac80211: pass bs... |
1201 1202 |
ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems, mgmt->bssid, NULL); |
ecbc12ad6 {nl,mac}80211: ad... |
1203 |
mesh_process_plink_frame(sdata, mgmt, &elems, rx_status); |
05a23ae92 mac80211: factor ... |
1204 |
} |