Blame view
net/mac80211/mesh.c
44.2 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
2e3c87368 mac80211: support... |
2 |
/* |
264d9b7d8 mac80211: update ... |
3 |
* Copyright (c) 2008, 2009 open80211s Ltd. |
2a333a0db mac80211: avoid u... |
4 |
* Copyright (C) 2018 - 2020 Intel Corporation |
2e3c87368 mac80211: support... |
5 6 |
* Authors: Luis Carlos Cobo <luisca@cozybit.com> * Javier Cardona <javier@cozybit.com> |
2e3c87368 mac80211: support... |
7 |
*/ |
5a0e3ad6a include cleanup: ... |
8 |
#include <linux/slab.h> |
51ceddade mac80211: use 4-b... |
9 |
#include <asm/unaligned.h> |
2e3c87368 mac80211: support... |
10 11 |
#include "ieee80211_i.h" #include "mesh.h" |
b8456a14e {nl,cfg,mac}80211... |
12 |
#include "driver-ops.h" |
2e3c87368 mac80211: support... |
13 |
|
bf7cd94dc mac80211: clean u... |
14 |
static int mesh_allocated; |
2e3c87368 mac80211: support... |
15 |
static struct kmem_cache *rm_cache; |
25d49e4d6 mac80211: update ... |
16 17 18 19 20 |
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt) { return (mgmt->u.action.u.mesh_action.action_code == WLAN_MESH_ACTION_HWMP_PATH_SELECTION); } |
25d49e4d6 mac80211: update ... |
21 |
|
2e3c87368 mac80211: support... |
22 23 |
void ieee80211s_init(void) { |
2e3c87368 mac80211: support... |
24 25 26 27 28 29 30 |
mesh_allocated = 1; rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry), 0, 0, NULL); } void ieee80211s_stop(void) { |
bf7cd94dc mac80211: clean u... |
31 32 |
if (!mesh_allocated) return; |
2e3c87368 mac80211: support... |
33 34 |
kmem_cache_destroy(rm_cache); } |
34f11cd32 mac80211: Convert... |
35 |
static void ieee80211_mesh_housekeeping_timer(struct timer_list *t) |
472dbc45d mac80211: split o... |
36 |
{ |
34f11cd32 mac80211: Convert... |
37 38 |
struct ieee80211_sub_if_data *sdata = from_timer(sdata, t, u.mesh.housekeeping_timer); |
472dbc45d mac80211: split o... |
39 40 |
struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
6b9ac4425 mesh: use set_bit... |
41 |
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
5bb644a0f mac80211: cancel/... |
42 |
|
64592c8fc mac80211: use com... |
43 |
ieee80211_queue_work(&local->hw, &sdata->work); |
472dbc45d mac80211: split o... |
44 |
} |
2e3c87368 mac80211: support... |
45 46 47 |
/** * mesh_matches_local - check if the config of a mesh point matches ours * |
f698d856f replace net_devic... |
48 |
* @sdata: local mesh subif |
f743ff490 mac80211: refacto... |
49 |
* @ie: information elements of a management frame from the mesh peer |
2e3c87368 mac80211: support... |
50 51 52 53 |
* * This function checks if the mesh configuration of a mesh point matches the * local mesh configuration, i.e. if both nodes belong to the same mesh network. */ |
f743ff490 mac80211: refacto... |
54 55 |
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *ie) |
2e3c87368 mac80211: support... |
56 |
{ |
472dbc45d mac80211: split o... |
57 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
f743ff490 mac80211: refacto... |
58 |
u32 basic_rates = 0; |
4bf88530b mac80211: convert... |
59 |
struct cfg80211_chan_def sta_chan_def; |
21a8e9dd5 mac80211: Fix pos... |
60 |
struct ieee80211_supported_band *sband; |
2a333a0db mac80211: avoid u... |
61 |
u32 vht_cap_info = 0; |
2e3c87368 mac80211: support... |
62 |
|
2e3c87368 mac80211: support... |
63 64 65 66 67 68 69 70 71 72 |
/* * As support for each feature is added, check for matching * - On mesh config capabilities * - Power Save Support En * - Sync support enabled * - Sync support active * - Sync support required from peer * - MDA enabled * - Power management control on fc */ |
739522baa mac80211: set HT ... |
73 74 75 76 77 78 79 |
if (!(ifmsh->mesh_id_len == ie->mesh_id_len && memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) && (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) && (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) && (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) && (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) |
bf7cd94dc mac80211: clean u... |
80 |
return false; |
739522baa mac80211: set HT ... |
81 |
|
21a8e9dd5 mac80211: Fix pos... |
82 83 84 85 86 |
sband = ieee80211_get_sband(sdata); if (!sband) return false; ieee80211_sta_get_rates(sdata, ie, sband->band, |
f743ff490 mac80211: refacto... |
87 |
&basic_rates); |
fe40cb627 mac80211: Check b... |
88 |
if (sdata->vif.bss_conf.basic_rates != basic_rates) |
bf7cd94dc mac80211: clean u... |
89 |
return false; |
fe40cb627 mac80211: Check b... |
90 |
|
8ac3c7041 mac80211: refacto... |
91 92 93 |
cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan, NL80211_CHAN_NO_HT); ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def); |
2a333a0db mac80211: avoid u... |
94 95 96 97 98 |
if (ie->vht_cap_elem) vht_cap_info = le32_to_cpu(ie->vht_cap_elem->vht_cap_info); ieee80211_chandef_vht_oper(&sdata->local->hw, vht_cap_info, |
7eb26df29 mac80211: add abi... |
99 100 |
ie->vht_operation, ie->ht_operation, &sta_chan_def); |
57fa5e85d mac80211: determi... |
101 |
ieee80211_chandef_he_6ghz_oper(sdata, ie->he_operation, &sta_chan_def); |
c85fb53c4 mac80211: impleme... |
102 |
|
4bf88530b mac80211: convert... |
103 104 |
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, &sta_chan_def)) |
bf7cd94dc mac80211: clean u... |
105 |
return false; |
2e3c87368 mac80211: support... |
106 |
|
739522baa mac80211: set HT ... |
107 |
return true; |
2e3c87368 mac80211: support... |
108 109 110 111 112 113 |
} /** * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links * * @ie: information elements of a management frame from the mesh peer |
2e3c87368 mac80211: support... |
114 |
*/ |
f698d856f replace net_devic... |
115 |
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
2e3c87368 mac80211: support... |
116 |
{ |
136cfa286 mac80211: use a s... |
117 |
return (ie->mesh_config->meshconf_cap & |
bf7cd94dc mac80211: clean u... |
118 |
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; |
2e3c87368 mac80211: support... |
119 120 121 |
} /** |
2c53040f0 net: Fix (nearly-... |
122 |
* mesh_accept_plinks_update - update accepting_plink in local mesh beacons |
2e3c87368 mac80211: support... |
123 |
* |
d0709a651 mac80211: RCU-ify... |
124 |
* @sdata: mesh interface in which mesh beacons are going to be updated |
df3238189 mac80211: fix unn... |
125 126 |
* * Returns: beacon changed flag if the beacon content changed. |
2e3c87368 mac80211: support... |
127 |
*/ |
df3238189 mac80211: fix unn... |
128 |
u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
129 |
{ |
2e3c87368 mac80211: support... |
130 |
bool free_plinks; |
df3238189 mac80211: fix unn... |
131 |
u32 changed = 0; |
2e3c87368 mac80211: support... |
132 133 134 |
/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, * the mesh interface might be able to establish plinks with peers that |
b4e08ea14 mac80211: add PLI... |
135 136 137 |
* are already on the table but are not on PLINK_ESTAB state. However, * in general the mesh interface is not accepting peer link requests * from new peers, and that must be reflected in the beacon |
2e3c87368 mac80211: support... |
138 139 |
*/ free_plinks = mesh_plink_availables(sdata); |
df3238189 mac80211: fix unn... |
140 141 142 143 144 145 |
if (free_plinks != sdata->u.mesh.accepting_plinks) { sdata->u.mesh.accepting_plinks = free_plinks; changed = BSS_CHANGED_BEACON; } return changed; |
2e3c87368 mac80211: support... |
146 |
} |
45b5028e8 mac80211: fix mes... |
147 148 149 150 151 152 153 154 |
/* * mesh_sta_cleanup - clean up any mesh sta state * * @sta: mesh sta to clean up. */ void mesh_sta_cleanup(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; |
efc401f49 mac80211: use com... |
155 |
u32 changed = mesh_plink_deactivate(sta); |
fe7a7c576 mac80211: mesh: f... |
156 |
|
f81a9deda mac80211: update ... |
157 |
if (changed) |
2b5e19677 mac80211: cache m... |
158 |
ieee80211_mbss_info_change_notify(sdata, changed); |
45b5028e8 mac80211: fix mes... |
159 |
} |
f698d856f replace net_devic... |
160 |
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
161 |
{ |
2e3c87368 mac80211: support... |
162 |
int i; |
472dbc45d mac80211: split o... |
163 164 |
sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); if (!sdata->u.mesh.rmc) |
2e3c87368 mac80211: support... |
165 |
return -ENOMEM; |
472dbc45d mac80211: split o... |
166 |
sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; |
2e3c87368 mac80211: support... |
167 |
for (i = 0; i < RMC_BUCKETS; i++) |
47a0489ce mac80211: mesh: u... |
168 |
INIT_HLIST_HEAD(&sdata->u.mesh.rmc->bucket[i]); |
2e3c87368 mac80211: support... |
169 170 |
return 0; } |
f698d856f replace net_devic... |
171 |
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
172 |
{ |
472dbc45d mac80211: split o... |
173 |
struct mesh_rmc *rmc = sdata->u.mesh.rmc; |
47a0489ce mac80211: mesh: u... |
174 175 |
struct rmc_entry *p; struct hlist_node *n; |
2e3c87368 mac80211: support... |
176 |
int i; |
472dbc45d mac80211: split o... |
177 |
if (!sdata->u.mesh.rmc) |
2e3c87368 mac80211: support... |
178 |
return; |
bf7cd94dc mac80211: clean u... |
179 |
for (i = 0; i < RMC_BUCKETS; i++) { |
47a0489ce mac80211: mesh: u... |
180 181 |
hlist_for_each_entry_safe(p, n, &rmc->bucket[i], list) { hlist_del(&p->list); |
2e3c87368 mac80211: support... |
182 183 |
kmem_cache_free(rm_cache, p); } |
bf7cd94dc mac80211: clean u... |
184 |
} |
2e3c87368 mac80211: support... |
185 186 |
kfree(rmc); |
472dbc45d mac80211: split o... |
187 |
sdata->u.mesh.rmc = NULL; |
2e3c87368 mac80211: support... |
188 189 190 191 192 |
} /** * mesh_rmc_check - Check frame in recent multicast cache and add if absent. * |
bf7cd94dc mac80211: clean u... |
193 |
* @sdata: interface |
2e3c87368 mac80211: support... |
194 195 196 197 198 199 200 201 202 |
* @sa: source address * @mesh_hdr: mesh_header * * Returns: 0 if the frame is not in the cache, nonzero otherwise. * * Checks using the source address and the mesh sequence number if we have * received this frame lately. If the frame is not in the cache, it is added to * it. */ |
bf7cd94dc mac80211: clean u... |
203 204 |
int mesh_rmc_check(struct ieee80211_sub_if_data *sdata, const u8 *sa, struct ieee80211s_hdr *mesh_hdr) |
2e3c87368 mac80211: support... |
205 |
{ |
472dbc45d mac80211: split o... |
206 |
struct mesh_rmc *rmc = sdata->u.mesh.rmc; |
2e3c87368 mac80211: support... |
207 208 209 |
u32 seqnum = 0; int entries = 0; u8 idx; |
47a0489ce mac80211: mesh: u... |
210 211 |
struct rmc_entry *p; struct hlist_node *n; |
2e3c87368 mac80211: support... |
212 |
|
0aa7fabbd mac80211: mesh: h... |
213 214 |
if (!rmc) return -1; |
2e3c87368 mac80211: support... |
215 |
/* Don't care about endianness since only match matters */ |
51ceddade mac80211: use 4-b... |
216 217 |
memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask; |
47a0489ce mac80211: mesh: u... |
218 |
hlist_for_each_entry_safe(p, n, &rmc->bucket[idx], list) { |
2e3c87368 mac80211: support... |
219 220 |
++entries; if (time_after(jiffies, p->exp_time) || |
bf7cd94dc mac80211: clean u... |
221 |
entries == RMC_QUEUE_MAX_LEN) { |
47a0489ce mac80211: mesh: u... |
222 |
hlist_del(&p->list); |
2e3c87368 mac80211: support... |
223 224 |
kmem_cache_free(rm_cache, p); --entries; |
bf7cd94dc mac80211: clean u... |
225 |
} else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa)) |
2e3c87368 mac80211: support... |
226 227 228 229 |
return -1; } p = kmem_cache_alloc(rm_cache, GFP_ATOMIC); |
d15b84590 mac80211: Remove ... |
230 |
if (!p) |
2e3c87368 mac80211: support... |
231 |
return 0; |
d15b84590 mac80211: Remove ... |
232 |
|
2e3c87368 mac80211: support... |
233 234 235 |
p->seqnum = seqnum; p->exp_time = jiffies + RMC_TIMEOUT; memcpy(p->sa, sa, ETH_ALEN); |
47a0489ce mac80211: mesh: u... |
236 |
hlist_add_head(&p->list, &rmc->bucket[idx]); |
2e3c87368 mac80211: support... |
237 238 |
return 0; } |
bf7cd94dc mac80211: clean u... |
239 240 |
int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
241 242 243 244 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 *pos, neighbors; u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie); |
4a6ecd35f mac80211: mesh: a... |
245 |
bool is_connected_to_gate = ifmsh->num_gates > 0 || |
01d66fbd5 {nl,mac}80211: ad... |
246 247 |
ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol || ifmsh->mshcfg.dot11MeshConnectedToMeshGate; |
184eebe66 cfg80211/mac80211... |
248 |
bool is_connected_to_as = ifmsh->mshcfg.dot11MeshConnectedToAuthServer; |
082ebb0c2 mac80211: fix mes... |
249 250 251 252 253 254 255 |
if (skb_tailroom(skb) < 2 + meshconf_len) return -ENOMEM; pos = skb_put(skb, 2 + meshconf_len); *pos++ = WLAN_EID_MESH_CONFIG; *pos++ = meshconf_len; |
43552be1d mac80211: update ... |
256 257 |
/* save a pointer for quick updates in pre-tbtt */ ifmsh->meshconf_offset = pos - skb->data; |
082ebb0c2 mac80211: fix mes... |
258 259 260 261 262 263 264 265 266 267 268 |
/* Active path selection protocol ID */ *pos++ = ifmsh->mesh_pp_id; /* Active path selection metric ID */ *pos++ = ifmsh->mesh_pm_id; /* Congestion control mode identifier */ *pos++ = ifmsh->mesh_cc_id; /* Synchronization protocol identifier */ *pos++ = ifmsh->mesh_sp_id; /* Authentication Protocol identifier */ *pos++ = ifmsh->mesh_auth_id; /* Mesh Formation Info - number of neighbors */ |
1258d9761 mac80211: move ou... |
269 |
neighbors = atomic_read(&ifmsh->estab_plinks); |
e05ecccdf mac80211: set mes... |
270 |
neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS); |
184eebe66 cfg80211/mac80211... |
271 272 273 |
*pos++ = (is_connected_to_as << 7) | (neighbors << 1) | is_connected_to_gate; |
082ebb0c2 mac80211: fix mes... |
274 |
/* Mesh capability */ |
b60e527a7 mac80211: set for... |
275 276 277 |
*pos = 0x00; *pos |= ifmsh->mshcfg.dot11MeshForwarding ? IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00; |
dbf498fba mac80211: Impleme... |
278 |
*pos |= ifmsh->accepting_plinks ? |
bf7cd94dc mac80211: clean u... |
279 |
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
3f52b7e32 mac80211: mesh po... |
280 281 |
/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */ *pos |= ifmsh->ps_peers_deep_sleep ? |
bf7cd94dc mac80211: clean u... |
282 |
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00; |
082ebb0c2 mac80211: fix mes... |
283 284 |
return 0; } |
bf7cd94dc mac80211: clean u... |
285 |
int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 *pos; if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len) return -ENOMEM; pos = skb_put(skb, 2 + ifmsh->mesh_id_len); *pos++ = WLAN_EID_MESH_ID; *pos++ = ifmsh->mesh_id_len; if (ifmsh->mesh_id_len) memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len); return 0; } |
bf7cd94dc mac80211: clean u... |
301 302 |
static int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
3f52b7e32 mac80211: mesh po... |
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 *pos; /* see IEEE802.11-2012 13.14.6 */ if (ifmsh->ps_peers_light_sleep == 0 && ifmsh->ps_peers_deep_sleep == 0 && ifmsh->nonpeer_pm == NL80211_MESH_POWER_ACTIVE) return 0; if (skb_tailroom(skb) < 4) return -ENOMEM; pos = skb_put(skb, 2 + 2); *pos++ = WLAN_EID_MESH_AWAKE_WINDOW; *pos++ = 2; put_unaligned_le16(ifmsh->mshcfg.dot11MeshAwakeWindowDuration, pos); return 0; } |
bf7cd94dc mac80211: clean u... |
323 324 |
int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
325 326 327 328 329 330 331 332 333 334 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 offset, len; const u8 *data; if (!ifmsh->ie || !ifmsh->ie_len) return 0; /* fast-forward to vendor IEs */ offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0); |
da7061c82 mac80211: Fix add... |
335 |
if (offset < ifmsh->ie_len) { |
082ebb0c2 mac80211: fix mes... |
336 337 338 339 |
len = ifmsh->ie_len - offset; data = ifmsh->ie + offset; if (skb_tailroom(skb) < len) return -ENOMEM; |
59ae1d127 networking: intro... |
340 |
skb_put_data(skb, data, len); |
082ebb0c2 mac80211: fix mes... |
341 342 343 344 |
} return 0; } |
bf7cd94dc mac80211: clean u... |
345 |
int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
346 347 348 349 350 351 352 353 354 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 len = 0; const u8 *data; if (!ifmsh->ie || !ifmsh->ie_len) return 0; /* find RSN IE */ |
a40a8c17b mac80211: fix mes... |
355 356 357 |
data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len); if (!data) return 0; |
082ebb0c2 mac80211: fix mes... |
358 |
|
a40a8c17b mac80211: fix mes... |
359 360 361 362 |
len = data[1] + 2; if (skb_tailroom(skb) < len) return -ENOMEM; |
59ae1d127 networking: intro... |
363 |
skb_put_data(skb, data, len); |
082ebb0c2 mac80211: fix mes... |
364 365 366 |
return 0; } |
bf7cd94dc mac80211: clean u... |
367 368 |
static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
369 |
{ |
55de908ab mac80211: use cha... |
370 371 |
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *chan; |
082ebb0c2 mac80211: fix mes... |
372 |
u8 *pos; |
2e3c87368 mac80211: support... |
373 |
|
082ebb0c2 mac80211: fix mes... |
374 375 |
if (skb_tailroom(skb) < 3) return -ENOMEM; |
55de908ab mac80211: use cha... |
376 377 378 379 380 381 |
rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; } |
4bf88530b mac80211: convert... |
382 |
chan = chanctx_conf->def.chan; |
55de908ab mac80211: use cha... |
383 |
rcu_read_unlock(); |
601513aa2 mac80211: Add the... |
384 385 386 387 |
pos = skb_put(skb, 2 + 1); *pos++ = WLAN_EID_DS_PARAMS; *pos++ = 1; *pos++ = ieee80211_frequency_to_channel(chan->center_freq); |
be125c60e mac80211: add the... |
388 |
|
082ebb0c2 mac80211: fix mes... |
389 |
return 0; |
2e3c87368 mac80211: support... |
390 |
} |
bf7cd94dc mac80211: clean u... |
391 392 |
int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
176f36086 mac80211: add HT ... |
393 |
{ |
176f36086 mac80211: add HT ... |
394 395 |
struct ieee80211_supported_band *sband; u8 *pos; |
21a8e9dd5 mac80211: Fix pos... |
396 397 398 |
sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; |
607ca9ea3 mac80211: do not ... |
399 400 401 |
/* HT not allowed in 6 GHz */ if (sband->band == NL80211_BAND_6GHZ) return 0; |
176f36086 mac80211: add HT ... |
402 |
if (!sband->ht_cap.ht_supported || |
0418a4458 mac80211: fix var... |
403 404 405 |
sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) |
176f36086 mac80211: add HT ... |
406 407 408 409 410 411 |
return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) return -ENOMEM; pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap)); |
ef96a8420 mac80211: Support... |
412 |
ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); |
176f36086 mac80211: add HT ... |
413 414 415 |
return 0; } |
bf7cd94dc mac80211: clean u... |
416 417 |
int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
176f36086 mac80211: add HT ... |
418 419 |
{ struct ieee80211_local *local = sdata->local; |
55de908ab mac80211: use cha... |
420 421 |
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *channel; |
55de908ab mac80211: use cha... |
422 423 |
struct ieee80211_supported_band *sband; struct ieee80211_sta_ht_cap *ht_cap; |
176f36086 mac80211: add HT ... |
424 |
u8 *pos; |
55de908ab mac80211: use cha... |
425 426 427 428 429 430 |
rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; } |
4bf88530b mac80211: convert... |
431 |
channel = chanctx_conf->def.chan; |
55de908ab mac80211: use cha... |
432 433 434 435 |
rcu_read_unlock(); sband = local->hw.wiphy->bands[channel->band]; ht_cap = &sband->ht_cap; |
607ca9ea3 mac80211: do not ... |
436 437 438 |
/* HT not allowed in 6 GHz */ if (sband->band == NL80211_BAND_6GHZ) return 0; |
c85fb53c4 mac80211: impleme... |
439 440 441 442 |
if (!ht_cap->ht_supported || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) |
176f36086 mac80211: add HT ... |
443 |
return 0; |
074d46d1d wireless: rename ... |
444 |
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation)) |
176f36086 mac80211: add HT ... |
445 |
return -ENOMEM; |
074d46d1d wireless: rename ... |
446 |
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); |
4bf88530b mac80211: convert... |
447 |
ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef, |
57f255f58 mac80211: TDLS: a... |
448 449 |
sdata->vif.bss_conf.ht_operation_mode, false); |
176f36086 mac80211: add HT ... |
450 451 452 |
return 0; } |
bf7cd94dc mac80211: clean u... |
453 |
|
c85fb53c4 mac80211: impleme... |
454 455 456 |
int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { |
c85fb53c4 mac80211: impleme... |
457 458 |
struct ieee80211_supported_band *sband; u8 *pos; |
21a8e9dd5 mac80211: Fix pos... |
459 460 461 |
sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; |
607ca9ea3 mac80211: do not ... |
462 463 464 |
/* VHT not allowed in 6 GHz */ if (sband->band == NL80211_BAND_6GHZ) return 0; |
c85fb53c4 mac80211: impleme... |
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
if (!sband->vht_cap.vht_supported || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap)) return -ENOMEM; pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_cap)); ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, sband->vht_cap.cap); return 0; } int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_local *local = sdata->local; struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *channel; struct ieee80211_supported_band *sband; struct ieee80211_sta_vht_cap *vht_cap; u8 *pos; rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; } channel = chanctx_conf->def.chan; rcu_read_unlock(); sband = local->hw.wiphy->bands[channel->band]; vht_cap = &sband->vht_cap; |
607ca9ea3 mac80211: do not ... |
501 502 503 |
/* VHT not allowed in 6 GHz */ if (sband->band == NL80211_BAND_6GHZ) return 0; |
c85fb53c4 mac80211: impleme... |
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
if (!vht_cap->vht_supported || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_operation)) return -ENOMEM; pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation)); ieee80211_ie_build_vht_oper(pos, vht_cap, &sdata->vif.bss_conf.chandef); return 0; } |
60ad72da5 mac80211: impleme... |
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 |
int mesh_add_he_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, u8 ie_len) { const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_supported_band *sband; u8 *pos; sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); if (!he_cap || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) return 0; if (skb_tailroom(skb) < ie_len) return -ENOMEM; pos = skb_put(skb, ie_len); ieee80211_ie_build_he_cap(pos, he_cap, pos + ie_len); return 0; } int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_supported_band *sband; |
d1b7524b3 mac80211: build H... |
552 |
u32 len; |
60ad72da5 mac80211: impleme... |
553 554 555 556 557 558 559 560 561 562 563 564 |
u8 *pos; sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; he_cap = ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_MESH_POINT); if (!he_cap || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) return 0; |
d1b7524b3 mac80211: build H... |
565 566 567 568 569 |
len = 2 + 1 + sizeof(struct ieee80211_he_operation); if (sdata->vif.bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) len += sizeof(struct ieee80211_he_6ghz_oper); if (skb_tailroom(skb) < len) |
60ad72da5 mac80211: impleme... |
570 |
return -ENOMEM; |
d1b7524b3 mac80211: build H... |
571 572 |
pos = skb_put(skb, len); ieee80211_ie_build_he_oper(pos, &sdata->vif.bss_conf.chandef); |
60ad72da5 mac80211: impleme... |
573 574 575 |
return 0; } |
24a2042cb mac80211: add HE ... |
576 577 578 |
int mesh_add_he_6ghz_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { |
65ad3ef9f mac80211: fix war... |
579 580 581 582 583 584 585 586 587 588 589 590 |
struct ieee80211_supported_band *sband; const struct ieee80211_sband_iftype_data *iftd; sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; iftd = ieee80211_get_sband_iftype_data(sband, NL80211_IFTYPE_MESH_POINT); /* The device doesn't support HE in mesh mode or at all */ if (!iftd) return 0; |
24a2042cb mac80211: add HE ... |
591 592 593 |
ieee80211_ie_build_he_6ghz_cap(sdata, skb); return 0; } |
34f11cd32 mac80211: Convert... |
594 |
static void ieee80211_mesh_path_timer(struct timer_list *t) |
2e3c87368 mac80211: support... |
595 596 |
{ struct ieee80211_sub_if_data *sdata = |
34f11cd32 mac80211: Convert... |
597 |
from_timer(sdata, t, u.mesh.mesh_path_timer); |
5bb644a0f mac80211: cancel/... |
598 |
|
690205f18 mac80211: cleanup... |
599 |
ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
2e3c87368 mac80211: support... |
600 |
} |
34f11cd32 mac80211: Convert... |
601 |
static void ieee80211_mesh_path_root_timer(struct timer_list *t) |
e304bfd30 mac80211: impleme... |
602 603 |
{ struct ieee80211_sub_if_data *sdata = |
34f11cd32 mac80211: Convert... |
604 |
from_timer(sdata, t, u.mesh.mesh_path_root_timer); |
e304bfd30 mac80211: impleme... |
605 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
e304bfd30 mac80211: impleme... |
606 607 |
set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); |
690205f18 mac80211: cleanup... |
608 |
ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
e304bfd30 mac80211: impleme... |
609 |
} |
63c5723bc mac80211: add nl8... |
610 611 |
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) { |
dbb912cd4 mac80211: invoke ... |
612 |
if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT) |
63c5723bc mac80211: add nl8... |
613 614 615 616 617 618 619 |
set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); else { clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); /* stop running timer */ del_timer_sync(&ifmsh->mesh_path_root_timer); } } |
902acc789 mac80211: clean u... |
620 |
/** |
3c5772a52 mac80211: Use 3-a... |
621 |
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame |
bf7cd94dc mac80211: clean u... |
622 |
* @hdr: 802.11 frame header |
3c5772a52 mac80211: Use 3-a... |
623 624 |
* @fc: frame control field * @meshda: destination address in the mesh |
13880a3b5 net: mac80211: me... |
625 |
* @meshsa: source address in the mesh. Same as TA, as frame is |
3c5772a52 mac80211: Use 3-a... |
626 627 628 629 |
* locally originated. * * Return the length of the 802.11 (does not include a mesh control header) */ |
15ff63653 mac80211: use fix... |
630 631 632 |
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, const u8 *meshda, const u8 *meshsa) { |
3c5772a52 mac80211: Use 3-a... |
633 634 635 636 637 638 639 640 |
if (is_multicast_ether_addr(meshda)) { *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA TA SA */ memcpy(hdr->addr1, meshda, ETH_ALEN); memcpy(hdr->addr2, meshsa, ETH_ALEN); memcpy(hdr->addr3, meshsa, ETH_ALEN); return 24; } else { |
2154c81c3 mac80211: Mesh da... |
641 |
*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
3c5772a52 mac80211: Use 3-a... |
642 |
/* RA TA DA SA */ |
c84a67a2f mac80211: Use eth... |
643 |
eth_zero_addr(hdr->addr1); /* RA is resolved later */ |
3c5772a52 mac80211: Use 3-a... |
644 645 646 647 648 649 650 651 |
memcpy(hdr->addr2, meshsa, ETH_ALEN); memcpy(hdr->addr3, meshda, ETH_ALEN); memcpy(hdr->addr4, meshsa, ETH_ALEN); return 30; } } /** |
902acc789 mac80211: clean u... |
652 |
* ieee80211_new_mesh_header - create a new mesh header |
902acc789 mac80211: clean u... |
653 |
* @sdata: mesh interface to be used |
bf7cd94dc mac80211: clean u... |
654 |
* @meshhdr: uninitialized mesh header |
61ad53945 mac80211: Remove ... |
655 656 657 658 659 |
* @addr4or5: 1st address in the ae header, which may correspond to address 4 * (if addr6 is NULL) or address 5 (if addr6 is present). It may * be NULL. * @addr6: 2nd address in the ae header, which corresponds to addr6 of the * mesh frame |
902acc789 mac80211: clean u... |
660 661 662 |
* * Return the header length. */ |
5edfcee5e mac80211: make ie... |
663 664 665 |
unsigned int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata, struct ieee80211s_hdr *meshhdr, const char *addr4or5, const char *addr6) |
902acc789 mac80211: clean u... |
666 |
{ |
bf7cd94dc mac80211: clean u... |
667 668 |
if (WARN_ON(!addr4or5 && addr6)) return 0; |
0c3cee72a net/mac80211: Cor... |
669 |
memset(meshhdr, 0, sizeof(*meshhdr)); |
bf7cd94dc mac80211: clean u... |
670 |
|
472dbc45d mac80211: split o... |
671 |
meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
bf7cd94dc mac80211: clean u... |
672 673 |
/* FIXME: racy -- TX on multiple queues can be concurrent */ |
472dbc45d mac80211: split o... |
674 675 |
put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); sdata->u.mesh.mesh_seqnum++; |
bf7cd94dc mac80211: clean u... |
676 |
|
61ad53945 mac80211: Remove ... |
677 |
if (addr4or5 && !addr6) { |
3c5772a52 mac80211: Use 3-a... |
678 |
meshhdr->flags |= MESH_FLAGS_AE_A4; |
61ad53945 mac80211: Remove ... |
679 |
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); |
bf7cd94dc mac80211: clean u... |
680 |
return 2 * ETH_ALEN; |
61ad53945 mac80211: Remove ... |
681 |
} else if (addr4or5 && addr6) { |
3c5772a52 mac80211: Use 3-a... |
682 |
meshhdr->flags |= MESH_FLAGS_AE_A5_A6; |
61ad53945 mac80211: Remove ... |
683 684 |
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); |
bf7cd94dc mac80211: clean u... |
685 |
return 3 * ETH_ALEN; |
3c5772a52 mac80211: Use 3-a... |
686 |
} |
bf7cd94dc mac80211: clean u... |
687 688 |
return ETH_ALEN; |
902acc789 mac80211: clean u... |
689 |
} |
bf7cd94dc mac80211: clean u... |
690 |
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) |
472dbc45d mac80211: split o... |
691 |
{ |
bf7cd94dc mac80211: clean u... |
692 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
df3238189 mac80211: fix unn... |
693 |
u32 changed; |
472dbc45d mac80211: split o... |
694 |
|
31f909a2c nl/mac80211: allo... |
695 696 |
if (ifmsh->mshcfg.plink_timeout > 0) ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ); |
472dbc45d mac80211: split o... |
697 |
mesh_path_expire(sdata); |
df3238189 mac80211: fix unn... |
698 |
changed = mesh_accept_plinks_update(sdata); |
2b5e19677 mac80211: cache m... |
699 |
ieee80211_mbss_info_change_notify(sdata, changed); |
472dbc45d mac80211: split o... |
700 |
|
472dbc45d mac80211: split o... |
701 |
mod_timer(&ifmsh->housekeeping_timer, |
bf7cd94dc mac80211: clean u... |
702 703 |
round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
472dbc45d mac80211: split o... |
704 |
} |
e304bfd30 mac80211: impleme... |
705 706 707 |
static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
a69cc44fe mac80211: impleme... |
708 |
u32 interval; |
e304bfd30 mac80211: impleme... |
709 710 |
mesh_path_tx_root_frame(sdata); |
a69cc44fe mac80211: impleme... |
711 712 713 714 715 |
if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN) interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; else interval = ifmsh->mshcfg.dot11MeshHWMProotInterval; |
e304bfd30 mac80211: impleme... |
716 |
mod_timer(&ifmsh->mesh_path_root_timer, |
a69cc44fe mac80211: impleme... |
717 |
round_jiffies(TU_TO_EXP_TIME(interval))); |
e304bfd30 mac80211: impleme... |
718 |
} |
2b5e19677 mac80211: cache m... |
719 720 721 722 723 724 725 726 |
static int ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) { struct beacon_data *bcn; int head_len, tail_len; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; struct ieee80211_chanctx_conf *chanctx_conf; |
b8456a14e {nl,cfg,mac}80211... |
727 |
struct mesh_csa_settings *csa; |
57fbcce37 cfg80211: remove ... |
728 |
enum nl80211_band band; |
60ad72da5 mac80211: impleme... |
729 |
u8 ie_len_he_cap; |
2b5e19677 mac80211: cache m... |
730 731 |
u8 *pos; struct ieee80211_sub_if_data *sdata; |
4c121fd69 mac80211: use off... |
732 |
int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon); |
2b5e19677 mac80211: cache m... |
733 734 735 736 737 738 |
sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); band = chanctx_conf->def.chan->band; rcu_read_unlock(); |
60ad72da5 mac80211: impleme... |
739 740 |
ie_len_he_cap = ieee80211_ie_len_he_cap(sdata, NL80211_IFTYPE_MESH_POINT); |
2b5e19677 mac80211: cache m... |
741 742 |
head_len = hdr_len + 2 + /* NULL SSID */ |
b8456a14e {nl,cfg,mac}80211... |
743 744 |
/* Channel Switch Announcement */ 2 + sizeof(struct ieee80211_channel_sw_ie) + |
08a7e621f scripts/spelling.... |
745 |
/* Mesh Channel Switch Parameters */ |
b8456a14e {nl,cfg,mac}80211... |
746 |
2 + sizeof(struct ieee80211_mesh_chansw_params_ie) + |
75d627d53 mac80211: mesh: s... |
747 748 749 |
/* Channel Switch Wrapper + Wide Bandwidth CSA IE */ 2 + 2 + sizeof(struct ieee80211_wide_bw_chansw_ie) + 2 + sizeof(struct ieee80211_sec_chan_offs_ie) + |
2b5e19677 mac80211: cache m... |
750 751 752 753 754 755 756 757 |
2 + 8 + /* supported rates */ 2 + 3; /* DS params */ tail_len = 2 + (IEEE80211_MAX_SUPP_RATES - 8) + 2 + sizeof(struct ieee80211_ht_cap) + 2 + sizeof(struct ieee80211_ht_operation) + 2 + ifmsh->mesh_id_len + 2 + sizeof(struct ieee80211_meshconf_ie) + 2 + sizeof(__le16) + /* awake window */ |
c85fb53c4 mac80211: impleme... |
758 759 |
2 + sizeof(struct ieee80211_vht_cap) + 2 + sizeof(struct ieee80211_vht_operation) + |
60ad72da5 mac80211: impleme... |
760 761 |
ie_len_he_cap + 2 + 1 + sizeof(struct ieee80211_he_operation) + |
d1b7524b3 mac80211: build H... |
762 |
sizeof(struct ieee80211_he_6ghz_oper) + |
24a2042cb mac80211: add HE ... |
763 |
2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) + |
2b5e19677 mac80211: cache m... |
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 |
ifmsh->ie_len; bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL); /* need an skb for IE builders to operate on */ skb = dev_alloc_skb(max(head_len, tail_len)); if (!bcn || !skb) goto out_free; /* * pointers go into the block we allocated, * memory is | beacon_data | head | tail | */ bcn->head = ((u8 *) bcn) + sizeof(*bcn); /* fill in the head */ |
b080db585 networking: conve... |
780 |
mgmt = skb_put_zero(skb, hdr_len); |
2b5e19677 mac80211: cache m... |
781 782 783 784 785 786 787 788 789 790 791 792 793 794 |
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); eth_broadcast_addr(mgmt->da); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt); mgmt->u.beacon.beacon_int = cpu_to_le16(sdata->vif.bss_conf.beacon_int); mgmt->u.beacon.capab_info |= cpu_to_le16( sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0); pos = skb_put(skb, 2); *pos++ = WLAN_EID_SSID; *pos++ = 0x0; |
b8456a14e {nl,cfg,mac}80211... |
795 796 797 |
rcu_read_lock(); csa = rcu_dereference(ifmsh->csa); if (csa) { |
75d627d53 mac80211: mesh: s... |
798 799 800 801 |
enum nl80211_channel_type ct; struct cfg80211_chan_def *chandef; int ie_len = 2 + sizeof(struct ieee80211_channel_sw_ie) + 2 + sizeof(struct ieee80211_mesh_chansw_params_ie); |
e45a79da8 skbuff/mac80211: ... |
802 |
pos = skb_put_zero(skb, ie_len); |
b8456a14e {nl,cfg,mac}80211... |
803 804 805 806 807 |
*pos++ = WLAN_EID_CHANNEL_SWITCH; *pos++ = 3; *pos++ = 0x0; *pos++ = ieee80211_frequency_to_channel( csa->settings.chandef.chan->center_freq); |
8552a434b mac80211: rename ... |
808 809 |
bcn->cntdwn_current_counter = csa->settings.count; bcn->cntdwn_counter_offsets[0] = hdr_len + 6; |
b8456a14e {nl,cfg,mac}80211... |
810 811 812 |
*pos++ = csa->settings.count; *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; *pos++ = 6; |
0cb4d4dce mac80211: refacto... |
813 |
if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) { |
b8456a14e {nl,cfg,mac}80211... |
814 815 816 817 818 819 820 821 822 |
*pos++ = ifmsh->mshcfg.dot11MeshTTL; *pos |= WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; } else { *pos++ = ifmsh->chsw_ttl; } *pos++ |= csa->settings.block_tx ? WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00; put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); pos += 2; |
ca91dc97b mac80211: use put... |
823 |
put_unaligned_le16(ifmsh->pre_value, pos); |
b8456a14e {nl,cfg,mac}80211... |
824 |
pos += 2; |
75d627d53 mac80211: mesh: s... |
825 826 827 828 |
switch (csa->settings.chandef.width) { case NL80211_CHAN_WIDTH_40: ie_len = 2 + sizeof(struct ieee80211_sec_chan_offs_ie); |
e45a79da8 skbuff/mac80211: ... |
829 |
pos = skb_put_zero(skb, ie_len); |
75d627d53 mac80211: mesh: s... |
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 |
*pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; /* EID */ *pos++ = 1; /* len */ ct = cfg80211_get_chandef_type(&csa->settings.chandef); if (ct == NL80211_CHAN_HT40PLUS) *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; else *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW; break; case NL80211_CHAN_WIDTH_80: case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_160: /* Channel Switch Wrapper + Wide Bandwidth CSA IE */ ie_len = 2 + 2 + sizeof(struct ieee80211_wide_bw_chansw_ie); |
e45a79da8 skbuff/mac80211: ... |
845 |
pos = skb_put_zero(skb, ie_len); |
75d627d53 mac80211: mesh: s... |
846 847 848 849 850 851 852 853 854 855 |
*pos++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER; /* EID */ *pos++ = 5; /* len */ /* put sub IE */ chandef = &csa->settings.chandef; ieee80211_ie_build_wide_bw_cs(pos, chandef); break; default: break; } |
b8456a14e {nl,cfg,mac}80211... |
856 857 |
} rcu_read_unlock(); |
2b5e19677 mac80211: cache m... |
858 |
if (ieee80211_add_srates_ie(sdata, skb, true, band) || |
bf7cd94dc mac80211: clean u... |
859 |
mesh_add_ds_params_ie(sdata, skb)) |
2b5e19677 mac80211: cache m... |
860 861 862 863 864 865 866 867 868 869 |
goto out_free; bcn->head_len = skb->len; memcpy(bcn->head, skb->data, bcn->head_len); /* now the tail */ skb_trim(skb, 0); bcn->tail = bcn->head + bcn->head_len; if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) || |
bf7cd94dc mac80211: clean u... |
870 871 872 873 874 875 |
mesh_add_rsn_ie(sdata, skb) || mesh_add_ht_cap_ie(sdata, skb) || mesh_add_ht_oper_ie(sdata, skb) || mesh_add_meshid_ie(sdata, skb) || mesh_add_meshconf_ie(sdata, skb) || mesh_add_awake_window_ie(sdata, skb) || |
c85fb53c4 mac80211: impleme... |
876 877 |
mesh_add_vht_cap_ie(sdata, skb) || mesh_add_vht_oper_ie(sdata, skb) || |
60ad72da5 mac80211: impleme... |
878 879 |
mesh_add_he_cap_ie(sdata, skb, ie_len_he_cap) || mesh_add_he_oper_ie(sdata, skb) || |
24a2042cb mac80211: add HE ... |
880 |
mesh_add_he_6ghz_cap_ie(sdata, skb) || |
bf7cd94dc mac80211: clean u... |
881 |
mesh_add_vendor_ies(sdata, skb)) |
2b5e19677 mac80211: cache m... |
882 883 884 885 |
goto out_free; bcn->tail_len = skb->len; memcpy(bcn->tail, skb->data, bcn->tail_len); |
43552be1d mac80211: update ... |
886 887 |
bcn->meshconf = (struct ieee80211_meshconf_ie *) (bcn->tail + ifmsh->meshconf_offset); |
2b5e19677 mac80211: cache m... |
888 889 890 891 892 893 894 895 896 897 898 |
dev_kfree_skb(skb); rcu_assign_pointer(ifmsh->beacon, bcn); return 0; out_free: kfree(bcn); dev_kfree_skb(skb); return -ENOMEM; } static int |
8d61ffa5e cfg80211/mac80211... |
899 |
ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata) |
2b5e19677 mac80211: cache m... |
900 |
{ |
2b5e19677 mac80211: cache m... |
901 902 |
struct beacon_data *old_bcn; int ret; |
2b5e19677 mac80211: cache m... |
903 |
|
8d61ffa5e cfg80211/mac80211... |
904 905 906 |
old_bcn = rcu_dereference_protected(sdata->u.mesh.beacon, lockdep_is_held(&sdata->wdev.mtx)); ret = ieee80211_mesh_build_beacon(&sdata->u.mesh); |
2b5e19677 mac80211: cache m... |
907 908 |
if (ret) /* just reuse old beacon */ |
8d61ffa5e cfg80211/mac80211... |
909 |
return ret; |
2b5e19677 mac80211: cache m... |
910 911 912 |
if (old_bcn) kfree_rcu(old_bcn, rcu_head); |
8d61ffa5e cfg80211/mac80211... |
913 |
return 0; |
2b5e19677 mac80211: cache m... |
914 915 916 917 918 |
} void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed) { |
f81a9deda mac80211: update ... |
919 920 921 922 923 924 925 926 927 928 929 930 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; unsigned long bits = changed; u32 bit; if (!bits) return; /* if we race with running work, worst case this work becomes a noop */ for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE) set_bit(bit, &ifmsh->mbss_changed); set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags); ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
2b5e19677 mac80211: cache m... |
931 932 933 |
} int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) |
472dbc45d mac80211: split o... |
934 935 936 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; |
f4eabc918 mac80211: use sho... |
937 938 939 940 |
u32 changed = BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_HT | BSS_CHANGED_BASIC_RATES | |
dcbe73ca5 mac80211: notify ... |
941 942 |
BSS_CHANGED_BEACON_INT | BSS_CHANGED_MCAST_RATE; |
472dbc45d mac80211: split o... |
943 |
|
09b174702 mac80211: move me... |
944 945 946 947 |
local->fif_other_bss++; /* mesh ifaces must set allmulti to forward mcast traffic */ atomic_inc(&local->iff_allmultis); ieee80211_configure_filter(local); |
c7108a711 mac80211: Send me... |
948 |
ifmsh->mesh_cc_id = 0; /* Disabled */ |
dbf498fba mac80211: Impleme... |
949 950 |
/* register sync ops from extensible synchronization framework */ ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id); |
dbf498fba mac80211: Impleme... |
951 |
ifmsh->sync_offset_clockdrift_max = 0; |
6b9ac4425 mesh: use set_bit... |
952 |
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
63c5723bc mac80211: add nl8... |
953 |
ieee80211_mesh_root_setup(ifmsh); |
64592c8fc mac80211: use com... |
954 |
ieee80211_queue_work(&local->hw, &sdata->work); |
70c33eaae {nl,cfg,mac}80211... |
955 956 |
sdata->vif.bss_conf.ht_operation_mode = ifmsh->mshcfg.ht_opmode; |
d6a832288 mac80211: track e... |
957 |
sdata->vif.bss_conf.enable_beacon = true; |
f4eabc918 mac80211: use sho... |
958 |
|
39886b618 mac80211: consoli... |
959 |
changed |= ieee80211_mps_local_status_update(sdata); |
3f52b7e32 mac80211: mesh po... |
960 |
|
2b5e19677 mac80211: cache m... |
961 962 963 964 |
if (ieee80211_mesh_build_beacon(ifmsh)) { ieee80211_stop_mesh(sdata); return -ENOMEM; } |
057d5f4ba mac80211: sync dt... |
965 |
ieee80211_recalc_dtim(local, sdata); |
f4eabc918 mac80211: use sho... |
966 |
ieee80211_bss_info_change_notify(sdata, changed); |
c405c6298 mac80211: manage ... |
967 968 |
netif_carrier_on(sdata->dev); |
2b5e19677 mac80211: cache m... |
969 |
return 0; |
472dbc45d mac80211: split o... |
970 971 972 973 |
} void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) { |
09b174702 mac80211: move me... |
974 |
struct ieee80211_local *local = sdata->local; |
29cbe68c5 cfg80211/mac80211... |
975 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2b5e19677 mac80211: cache m... |
976 |
struct beacon_data *bcn; |
29cbe68c5 cfg80211/mac80211... |
977 |
|
c405c6298 mac80211: manage ... |
978 |
netif_carrier_off(sdata->dev); |
c37a54ac3 mac80211: mesh: f... |
979 980 |
/* flush STAs and mpaths on this iface */ sta_info_flush(sdata); |
0112fa557 mac80211: free pe... |
981 |
ieee80211_free_keys(sdata, true); |
c37a54ac3 mac80211: mesh: f... |
982 |
mesh_path_flush_by_iface(sdata); |
0d466b9c6 mac80211: improve... |
983 |
/* stop the beacon */ |
29cbe68c5 cfg80211/mac80211... |
984 |
ifmsh->mesh_id_len = 0; |
d6a832288 mac80211: track e... |
985 |
sdata->vif.bss_conf.enable_beacon = false; |
08fad438b mac80211: TX lega... |
986 |
sdata->beacon_rate_set = false; |
d6a832288 mac80211: track e... |
987 |
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
29cbe68c5 cfg80211/mac80211... |
988 |
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
c37a54ac3 mac80211: mesh: f... |
989 990 |
/* remove beacon */ |
2b5e19677 mac80211: cache m... |
991 |
bcn = rcu_dereference_protected(ifmsh->beacon, |
8d61ffa5e cfg80211/mac80211... |
992 |
lockdep_is_held(&sdata->wdev.mtx)); |
0c2bef462 mac80211: use RCU... |
993 |
RCU_INIT_POINTER(ifmsh->beacon, NULL); |
2b5e19677 mac80211: cache m... |
994 |
kfree_rcu(bcn, rcu_head); |
0d466b9c6 mac80211: improve... |
995 |
|
3f52b7e32 mac80211: mesh po... |
996 997 998 |
/* free all potentially still buffered group-addressed frames */ local->total_ps_buffered -= skb_queue_len(&ifmsh->ps.bc_buf); skb_queue_purge(&ifmsh->ps.bc_buf); |
472dbc45d mac80211: split o... |
999 |
del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
e304bfd30 mac80211: impleme... |
1000 |
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
dd4c9260e mac80211: cancel ... |
1001 |
del_timer_sync(&sdata->u.mesh.mesh_path_timer); |
09b174702 mac80211: move me... |
1002 |
|
f81a9deda mac80211: update ... |
1003 1004 1005 |
/* clear any mesh work (for next join) we may have accrued */ ifmsh->wrkq_flags = 0; ifmsh->mbss_changed = 0; |
09b174702 mac80211: move me... |
1006 1007 1008 |
local->fif_other_bss--; atomic_dec(&local->iff_allmultis); ieee80211_configure_filter(local); |
472dbc45d mac80211: split o... |
1009 |
} |
5d55371b2 mac80211: mesh: m... |
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 |
static void ieee80211_mesh_csa_mark_radar(struct ieee80211_sub_if_data *sdata) { int err; /* if the current channel is a DFS channel, mark the channel as * unavailable. */ err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, &sdata->vif.bss_conf.chandef, NL80211_IFTYPE_MESH_POINT); if (err > 0) cfg80211_radar_event(sdata->local->hw.wiphy, &sdata->vif.bss_conf.chandef, GFP_ATOMIC); } |
33a45867c mac80211: process... |
1024 1025 1026 1027 1028 1029 |
static bool ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, bool beacon) { struct cfg80211_csa_settings params; struct ieee80211_csa_ie csa_ie; |
33a45867c mac80211: process... |
1030 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
21a8e9dd5 mac80211: Fix pos... |
1031 |
struct ieee80211_supported_band *sband; |
0cb4d4dce mac80211: refacto... |
1032 |
int err; |
2a333a0db mac80211: avoid u... |
1033 |
u32 sta_flags, vht_cap_info = 0; |
33a45867c mac80211: process... |
1034 |
|
dbd72850d mac80211: add mis... |
1035 |
sdata_assert_lock(sdata); |
21a8e9dd5 mac80211: Fix pos... |
1036 1037 1038 |
sband = ieee80211_get_sband(sdata); if (!sband) return false; |
71ec289e6 mac80211: enable ... |
1039 |
sta_flags = 0; |
33a45867c mac80211: process... |
1040 1041 1042 |
switch (sdata->vif.bss_conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: sta_flags |= IEEE80211_STA_DISABLE_HT; |
fc0561dc6 mac80211: Use fal... |
1043 |
fallthrough; |
33a45867c mac80211: process... |
1044 1045 |
case NL80211_CHAN_WIDTH_20: sta_flags |= IEEE80211_STA_DISABLE_40MHZ; |
fc0561dc6 mac80211: Use fal... |
1046 |
fallthrough; |
71ec289e6 mac80211: enable ... |
1047 1048 |
case NL80211_CHAN_WIDTH_40: sta_flags |= IEEE80211_STA_DISABLE_VHT; |
33a45867c mac80211: process... |
1049 1050 1051 1052 |
break; default: break; } |
2a333a0db mac80211: avoid u... |
1053 1054 1055 |
if (elems->vht_cap_elem) vht_cap_info = le32_to_cpu(elems->vht_cap_elem->vht_cap_info); |
33a45867c mac80211: process... |
1056 |
memset(¶ms, 0, sizeof(params)); |
21a8e9dd5 mac80211: Fix pos... |
1057 |
err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band, |
2a333a0db mac80211: avoid u... |
1058 |
vht_cap_info, |
33a45867c mac80211: process... |
1059 1060 1061 1062 1063 1064 |
sta_flags, sdata->vif.addr, &csa_ie); if (err < 0) return false; if (err) return false; |
5d55371b2 mac80211: mesh: m... |
1065 1066 1067 1068 1069 |
/* Mark the channel unavailable if the reason for the switch is * regulatory. */ if (csa_ie.reason_code == WLAN_REASON_MESH_CHAN_REGULATORY) ieee80211_mesh_csa_mark_radar(sdata); |
33a45867c mac80211: process... |
1070 1071 |
params.chandef = csa_ie.chandef; params.count = csa_ie.count; |
33a45867c mac80211: process... |
1072 |
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, |
0ab2e55d3 mac80211: mesh: A... |
1073 1074 1075 |
IEEE80211_CHAN_DISABLED) || !cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef, NL80211_IFTYPE_MESH_POINT)) { |
33a45867c mac80211: process... |
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 |
sdata_info(sdata, "mesh STA %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting ", sdata->vif.addr, params.chandef.chan->center_freq, params.chandef.width, params.chandef.center_freq1, params.chandef.center_freq2); return false; } err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, |
2beb6dab2 cfg80211/mac80211... |
1088 1089 |
¶ms.chandef, NL80211_IFTYPE_MESH_POINT); |
33a45867c mac80211: process... |
1090 1091 |
if (err < 0) return false; |
0ab2e55d3 mac80211: mesh: A... |
1092 1093 1094 1095 1096 1097 1098 1099 1100 |
if (err > 0 && !ifmsh->userspace_handles_dfs) { sdata_info(sdata, "mesh STA %pM switches to channel requiring DFS (%d MHz, width:%d, CF1/2: %d/%d MHz), aborting ", sdata->vif.addr, params.chandef.chan->center_freq, params.chandef.width, params.chandef.center_freq1, params.chandef.center_freq2); |
33a45867c mac80211: process... |
1101 |
return false; |
0ab2e55d3 mac80211: mesh: A... |
1102 |
} |
2beb6dab2 cfg80211/mac80211... |
1103 1104 |
params.radar_required = err; |
33a45867c mac80211: process... |
1105 |
|
0cb4d4dce mac80211: refacto... |
1106 1107 1108 1109 1110 1111 1112 |
if (cfg80211_chandef_identical(¶ms.chandef, &sdata->vif.bss_conf.chandef)) { mcsa_dbg(sdata, "received csa with an identical chandef, ignoring "); return true; } |
33a45867c mac80211: process... |
1113 1114 1115 1116 1117 1118 1119 |
mcsa_dbg(sdata, "received channel switch announcement to go to channel %d MHz ", params.chandef.chan->center_freq); params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT; |
3f718fd84 mac80211: fix the... |
1120 |
if (beacon) { |
33a45867c mac80211: process... |
1121 |
ifmsh->chsw_ttl = csa_ie.ttl - 1; |
3f718fd84 mac80211: fix the... |
1122 1123 1124 1125 |
if (ifmsh->pre_value >= csa_ie.pre_value) return false; ifmsh->pre_value = csa_ie.pre_value; } |
33a45867c mac80211: process... |
1126 |
|
0cb4d4dce mac80211: refacto... |
1127 |
if (ifmsh->chsw_ttl >= ifmsh->mshcfg.dot11MeshTTL) |
3f718fd84 mac80211: fix the... |
1128 |
return false; |
33a45867c mac80211: process... |
1129 |
|
0cb4d4dce mac80211: refacto... |
1130 |
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_REPEATER; |
33a45867c mac80211: process... |
1131 |
|
0cb4d4dce mac80211: refacto... |
1132 1133 1134 |
if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev, ¶ms) < 0) return false; |
33a45867c mac80211: process... |
1135 1136 |
return true; |
33a45867c mac80211: process... |
1137 |
} |
9fb04b501 mac80211: generat... |
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 |
static void ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct sk_buff *presp; struct beacon_data *bcn; struct ieee80211_mgmt *hdr; struct ieee802_11_elems elems; size_t baselen; |
511044ea0 mac80211: remove ... |
1149 |
u8 *pos; |
9fb04b501 mac80211: generat... |
1150 |
|
9fb04b501 mac80211: generat... |
1151 1152 1153 1154 |
pos = mgmt->u.probe_req.variable; baselen = (u8 *) pos - (u8 *) mgmt; if (baselen > len) return; |
4abb52a46 mac80211: pass bs... |
1155 1156 |
ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid, NULL); |
9fb04b501 mac80211: generat... |
1157 |
|
a4ef66a91 mac80211: only re... |
1158 1159 |
if (!elems.mesh_id) return; |
9fb04b501 mac80211: generat... |
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 |
/* 802.11-2012 10.1.4.3.2 */ if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) && !is_broadcast_ether_addr(mgmt->da)) || elems.ssid_len != 0) return; if (elems.mesh_id_len != 0 && (elems.mesh_id_len != ifmsh->mesh_id_len || memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len))) return; rcu_read_lock(); bcn = rcu_dereference(ifmsh->beacon); if (!bcn) goto out; presp = dev_alloc_skb(local->tx_headroom + bcn->head_len + bcn->tail_len); if (!presp) goto out; skb_reserve(presp, local->tx_headroom); |
59ae1d127 networking: intro... |
1183 1184 |
skb_put_data(presp, bcn->head, bcn->head_len); skb_put_data(presp, bcn->tail, bcn->tail_len); |
9fb04b501 mac80211: generat... |
1185 1186 1187 1188 |
hdr = (struct ieee80211_mgmt *) presp->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); memcpy(hdr->da, mgmt->sa, ETH_ALEN); |
9fb04b501 mac80211: generat... |
1189 1190 1191 1192 1193 |
IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, presp); out: rcu_read_unlock(); } |
472dbc45d mac80211: split o... |
1194 1195 1196 1197 1198 1199 |
static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { |
c6a1fa12d mac80211: minor c... |
1200 |
struct ieee80211_local *local = sdata->local; |
dbf498fba mac80211: Impleme... |
1201 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
472dbc45d mac80211: split o... |
1202 1203 |
struct ieee802_11_elems elems; struct ieee80211_channel *channel; |
472dbc45d mac80211: split o... |
1204 1205 |
size_t baselen; int freq; |
57fbcce37 cfg80211: remove ... |
1206 |
enum nl80211_band band = rx_status->band; |
472dbc45d mac80211: split o... |
1207 1208 1209 |
/* ignore ProbeResp to foreign address */ if (stype == IEEE80211_STYPE_PROBE_RESP && |
b203ca391 mac80211: Convert... |
1210 |
!ether_addr_equal(mgmt->da, sdata->vif.addr)) |
472dbc45d mac80211: split o... |
1211 1212 1213 1214 1215 1216 1217 |
return; baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; if (baselen > len) return; ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
4abb52a46 mac80211: pass bs... |
1218 |
false, &elems, mgmt->bssid, NULL); |
472dbc45d mac80211: split o... |
1219 |
|
9a90bc819 mac80211: mesh ST... |
1220 1221 1222 1223 |
/* ignore non-mesh or secure / unsecure mismatch */ if ((!elems.mesh_id || !elems.mesh_config) || (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) |
5cff5e01e mac80211: ignore ... |
1224 |
return; |
1cd8e88e1 mac80211: check D... |
1225 |
if (elems.ds_params) |
59eb21a65 cfg80211: Extend ... |
1226 |
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); |
472dbc45d mac80211: split o... |
1227 1228 1229 1230 1231 1232 1233 |
else freq = rx_status->freq; channel = ieee80211_get_channel(local->hw.wiphy, freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) return; |
ed92a9b5d mac80211: mesh: d... |
1234 1235 1236 1237 1238 1239 1240 |
if (mesh_matches_local(sdata, &elems)) { mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d ", sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal); if (!sdata->u.mesh.user_mpm || sdata->u.mesh.mshcfg.rssi_threshold == 0 || sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal) |
ecbc12ad6 {nl,mac}80211: ad... |
1241 1242 |
mesh_neighbour_update(sdata, mgmt->sa, &elems, rx_status); |
93e2d04a1 mac80211: fix cha... |
1243 1244 1245 1246 |
if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && !sdata->vif.csa_active) ieee80211_mesh_process_chnswitch(sdata, &elems, true); |
ed92a9b5d mac80211: mesh: d... |
1247 |
} |
dbf498fba mac80211: Impleme... |
1248 1249 1250 1251 |
if (ifmsh->sync_ops) ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, &elems, rx_status); |
472dbc45d mac80211: split o... |
1252 |
} |
b8456a14e {nl,cfg,mac}80211... |
1253 1254 1255 1256 1257 |
int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_csa_settings *tmp_csa_settings; int ret = 0; |
faf046e72 mac80211: batch C... |
1258 |
int changed = 0; |
b8456a14e {nl,cfg,mac}80211... |
1259 1260 |
/* Reset the TTL value and Initiator flag */ |
0cb4d4dce mac80211: refacto... |
1261 |
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; |
b8456a14e {nl,cfg,mac}80211... |
1262 1263 1264 |
ifmsh->chsw_ttl = 0; /* Remove the CSA and MCSP elements from the beacon */ |
551842446 mac80211: mesh: f... |
1265 1266 |
tmp_csa_settings = rcu_dereference_protected(ifmsh->csa, lockdep_is_held(&sdata->wdev.mtx)); |
0c2bef462 mac80211: use RCU... |
1267 |
RCU_INIT_POINTER(ifmsh->csa, NULL); |
66e01cf99 mac80211: only se... |
1268 1269 |
if (tmp_csa_settings) kfree_rcu(tmp_csa_settings, rcu_head); |
b8456a14e {nl,cfg,mac}80211... |
1270 1271 1272 |
ret = ieee80211_mesh_rebuild_beacon(sdata); if (ret) return -EINVAL; |
faf046e72 mac80211: batch C... |
1273 |
changed |= BSS_CHANGED_BEACON; |
b8456a14e {nl,cfg,mac}80211... |
1274 1275 1276 |
mcsa_dbg(sdata, "complete switching to center freq %d MHz", sdata->vif.bss_conf.chandef.chan->center_freq); |
faf046e72 mac80211: batch C... |
1277 |
return changed; |
b8456a14e {nl,cfg,mac}80211... |
1278 1279 1280 |
} int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, |
66e01cf99 mac80211: only se... |
1281 |
struct cfg80211_csa_settings *csa_settings) |
b8456a14e {nl,cfg,mac}80211... |
1282 1283 1284 1285 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_csa_settings *tmp_csa_settings; int ret = 0; |
551842446 mac80211: mesh: f... |
1286 |
lockdep_assert_held(&sdata->wdev.mtx); |
b8456a14e {nl,cfg,mac}80211... |
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 |
tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings), GFP_ATOMIC); if (!tmp_csa_settings) return -ENOMEM; memcpy(&tmp_csa_settings->settings, csa_settings, sizeof(struct cfg80211_csa_settings)); rcu_assign_pointer(ifmsh->csa, tmp_csa_settings); ret = ieee80211_mesh_rebuild_beacon(sdata); if (ret) { tmp_csa_settings = rcu_dereference(ifmsh->csa); |
0c2bef462 mac80211: use RCU... |
1300 |
RCU_INIT_POINTER(ifmsh->csa, NULL); |
b8456a14e {nl,cfg,mac}80211... |
1301 1302 1303 |
kfree_rcu(tmp_csa_settings, rcu_head); return ret; } |
b58e81e96 mac80211: align i... |
1304 |
return BSS_CHANGED_BEACON; |
b8456a14e {nl,cfg,mac}80211... |
1305 |
} |
8f2535b92 mac80211: process... |
1306 |
static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, |
c4de37ee2 mac80211: mesh: f... |
1307 1308 |
struct ieee80211_mgmt *mgmt, size_t len, struct ieee802_11_elems *elems) |
8f2535b92 mac80211: process... |
1309 1310 1311 1312 |
{ struct ieee80211_mgmt *mgmt_fwd; struct sk_buff *skb; struct ieee80211_local *local = sdata->local; |
8f2535b92 mac80211: process... |
1313 1314 1315 1316 1317 |
skb = dev_alloc_skb(local->tx_headroom + len); if (!skb) return -ENOMEM; skb_reserve(skb, local->tx_headroom); |
4df864c1d networking: make ... |
1318 |
mgmt_fwd = skb_put(skb, len); |
8f2535b92 mac80211: process... |
1319 |
|
c4de37ee2 mac80211: mesh: f... |
1320 1321 1322 |
elems->mesh_chansw_params_ie->mesh_ttl--; elems->mesh_chansw_params_ie->mesh_flags &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; |
8f2535b92 mac80211: process... |
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 |
memcpy(mgmt_fwd, mgmt, len); eth_broadcast_addr(mgmt_fwd->da); memcpy(mgmt_fwd->sa, sdata->vif.addr, ETH_ALEN); memcpy(mgmt_fwd->bssid, sdata->vif.addr, ETH_ALEN); ieee80211_tx_skb(sdata, skb); return 0; } static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee802_11_elems elems; u16 pre_value; |
33a45867c mac80211: process... |
1339 |
bool fwd_csa = true; |
8f2535b92 mac80211: process... |
1340 |
size_t baselen; |
3f718fd84 mac80211: fix the... |
1341 |
u8 *pos; |
8f2535b92 mac80211: process... |
1342 1343 1344 1345 1346 1347 1348 1349 |
if (mgmt->u.action.u.measurement.action_code != WLAN_ACTION_SPCT_CHL_SWITCH) return; pos = mgmt->u.action.u.chan_switch.variable; baselen = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch.variable); |
4abb52a46 mac80211: pass bs... |
1350 1351 |
ieee802_11_parse_elems(pos, len - baselen, true, &elems, mgmt->bssid, NULL); |
8f2535b92 mac80211: process... |
1352 |
|
93e2d04a1 mac80211: fix cha... |
1353 1354 |
if (!mesh_matches_local(sdata, &elems)) return; |
3f718fd84 mac80211: fix the... |
1355 1356 |
ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl; if (!--ifmsh->chsw_ttl) |
8f2535b92 mac80211: process... |
1357 1358 1359 1360 1361 1362 1363 |
fwd_csa = false; pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value); if (ifmsh->pre_value >= pre_value) return; ifmsh->pre_value = pre_value; |
0cb4d4dce mac80211: refacto... |
1364 1365 |
if (!sdata->vif.csa_active && !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { |
33a45867c mac80211: process... |
1366 1367 1368 |
mcsa_dbg(sdata, "Failed to process CSA action frame"); return; } |
8f2535b92 mac80211: process... |
1369 1370 |
/* forward or re-broadcast the CSA frame */ if (fwd_csa) { |
c4de37ee2 mac80211: mesh: f... |
1371 |
if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0) |
8f2535b92 mac80211: process... |
1372 1373 |
mcsa_dbg(sdata, "Failed to forward the CSA frame"); } |
8f2535b92 mac80211: process... |
1374 |
} |
472dbc45d mac80211: split o... |
1375 1376 1377 1378 1379 1380 |
static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { switch (mgmt->u.action.category) { |
8db098507 mac80211: update ... |
1381 1382 1383 1384 1385 1386 1387 1388 |
case WLAN_CATEGORY_SELF_PROTECTED: switch (mgmt->u.action.u.self_prot.action_code) { case WLAN_SP_MESH_PEERING_OPEN: case WLAN_SP_MESH_PEERING_CLOSE: case WLAN_SP_MESH_PEERING_CONFIRM: mesh_rx_plink_frame(sdata, mgmt, len, rx_status); break; } |
472dbc45d mac80211: split o... |
1389 |
break; |
25d49e4d6 mac80211: update ... |
1390 1391 1392 |
case WLAN_CATEGORY_MESH_ACTION: if (mesh_action_is_path_sel(mgmt)) mesh_rx_path_sel_frame(sdata, mgmt, len); |
472dbc45d mac80211: split o... |
1393 |
break; |
8f2535b92 mac80211: process... |
1394 1395 1396 |
case WLAN_CATEGORY_SPECTRUM_MGMT: mesh_rx_csa_frame(sdata, mgmt, len); break; |
472dbc45d mac80211: split o... |
1397 1398 |
} } |
1fa57d017 mac80211: use com... |
1399 1400 |
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
472dbc45d mac80211: split o... |
1401 1402 |
{ struct ieee80211_rx_status *rx_status; |
472dbc45d mac80211: split o... |
1403 1404 |
struct ieee80211_mgmt *mgmt; u16 stype; |
ecccd072b mac80211: fix mes... |
1405 1406 1407 |
sdata_lock(sdata); /* mesh already went down */ |
1693d3441 mac80211: use sda... |
1408 |
if (!sdata->u.mesh.mesh_id_len) |
ecccd072b mac80211: fix mes... |
1409 |
goto out; |
f1d58c252 mac80211: push rx... |
1410 |
rx_status = IEEE80211_SKB_RXCB(skb); |
472dbc45d mac80211: split o... |
1411 1412 1413 1414 1415 1416 1417 1418 1419 |
mgmt = (struct ieee80211_mgmt *) skb->data; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; switch (stype) { case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len, rx_status); break; |
9fb04b501 mac80211: generat... |
1420 1421 1422 |
case IEEE80211_STYPE_PROBE_REQ: ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len); break; |
472dbc45d mac80211: split o... |
1423 1424 1425 1426 |
case IEEE80211_STYPE_ACTION: ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); break; } |
ecccd072b mac80211: fix mes... |
1427 1428 |
out: sdata_unlock(sdata); |
472dbc45d mac80211: split o... |
1429 |
} |
f81a9deda mac80211: update ... |
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 |
static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u32 bit, changed = 0; for_each_set_bit(bit, &ifmsh->mbss_changed, sizeof(changed) * BITS_PER_BYTE) { clear_bit(bit, &ifmsh->mbss_changed); changed |= BIT(bit); } if (sdata->vif.bss_conf.enable_beacon && (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_HT | BSS_CHANGED_BASIC_RATES | BSS_CHANGED_BEACON_INT))) if (ieee80211_mesh_rebuild_beacon(sdata)) return; ieee80211_bss_info_change_notify(sdata, changed); } |
1fa57d017 mac80211: use com... |
1451 |
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) |
472dbc45d mac80211: split o... |
1452 |
{ |
472dbc45d mac80211: split o... |
1453 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
472dbc45d mac80211: split o... |
1454 |
|
ecccd072b mac80211: fix mes... |
1455 1456 1457 |
sdata_lock(sdata); /* mesh already went down */ |
1693d3441 mac80211: use sda... |
1458 |
if (!sdata->u.mesh.mesh_id_len) |
ecccd072b mac80211: fix mes... |
1459 |
goto out; |
472dbc45d mac80211: split o... |
1460 1461 1462 1463 |
if (ifmsh->preq_queue_len && time_after(jiffies, ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) mesh_path_start_discovery(sdata); |
18889231e mac80211: Move mp... |
1464 |
if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) |
bf7cd94dc mac80211: clean u... |
1465 |
ieee80211_mesh_housekeeping(sdata); |
e304bfd30 mac80211: impleme... |
1466 1467 1468 |
if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) ieee80211_mesh_rootpath(sdata); |
dbf498fba mac80211: Impleme... |
1469 1470 |
if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) |
445cd452f mac80211: Use app... |
1471 |
mesh_sync_adjust_tsf(sdata); |
ecccd072b mac80211: fix mes... |
1472 |
|
f81a9deda mac80211: update ... |
1473 1474 |
if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags)) mesh_bss_info_changed(sdata); |
ecccd072b mac80211: fix mes... |
1475 1476 |
out: sdata_unlock(sdata); |
472dbc45d mac80211: split o... |
1477 |
} |
472dbc45d mac80211: split o... |
1478 |
|
902acc789 mac80211: clean u... |
1479 1480 |
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) { |
472dbc45d mac80211: split o... |
1481 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
ad2d223aa mac80211: assign ... |
1482 |
static u8 zero_addr[ETH_ALEN] = {}; |
472dbc45d mac80211: split o... |
1483 |
|
34f11cd32 mac80211: Convert... |
1484 1485 |
timer_setup(&ifmsh->housekeeping_timer, ieee80211_mesh_housekeeping_timer, 0); |
472dbc45d mac80211: split o... |
1486 |
|
472dbc45d mac80211: split o... |
1487 |
ifmsh->accepting_plinks = true; |
472dbc45d mac80211: split o... |
1488 |
atomic_set(&ifmsh->mpaths, 0); |
f698d856f replace net_devic... |
1489 |
mesh_rmc_init(sdata); |
472dbc45d mac80211: split o... |
1490 |
ifmsh->last_preq = jiffies; |
dca7e9430 {nl,cfg,mac}80211... |
1491 |
ifmsh->next_perr = jiffies; |
0cb4d4dce mac80211: refacto... |
1492 |
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; |
902acc789 mac80211: clean u... |
1493 1494 1495 |
/* Allocate all mesh structures when creating the first mesh interface. */ if (!mesh_allocated) ieee80211s_init(); |
2bdaf386f mac80211: mesh: m... |
1496 1497 |
mesh_pathtbl_init(sdata); |
34f11cd32 mac80211: Convert... |
1498 1499 1500 |
timer_setup(&ifmsh->mesh_path_timer, ieee80211_mesh_path_timer, 0); timer_setup(&ifmsh->mesh_path_root_timer, ieee80211_mesh_path_root_timer, 0); |
472dbc45d mac80211: split o... |
1501 |
INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
3f52b7e32 mac80211: mesh po... |
1502 |
skb_queue_head_init(&ifmsh->ps.bc_buf); |
472dbc45d mac80211: split o... |
1503 |
spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
dbf498fba mac80211: Impleme... |
1504 |
spin_lock_init(&ifmsh->sync_offset_lock); |
2b5e19677 mac80211: cache m... |
1505 |
RCU_INIT_POINTER(ifmsh->beacon, NULL); |
ad2d223aa mac80211: assign ... |
1506 1507 |
sdata->vif.bss_conf.bssid = zero_addr; |
472dbc45d mac80211: split o... |
1508 |
} |
0371a08fb mac80211: mesh: f... |
1509 1510 1511 1512 1513 1514 |
void ieee80211_mesh_teardown_sdata(struct ieee80211_sub_if_data *sdata) { mesh_rmc_free(sdata); mesh_pathtbl_unregister(sdata); } |