Blame view
net/mac80211/mesh.c
40.5 KB
2e3c87368 mac80211: support... |
1 |
/* |
264d9b7d8 mac80211: update ... |
2 |
* Copyright (c) 2008, 2009 open80211s Ltd. |
2e3c87368 mac80211: support... |
3 4 5 6 7 8 9 |
* Authors: Luis Carlos Cobo <luisca@cozybit.com> * Javier Cardona <javier@cozybit.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ |
5a0e3ad6a include cleanup: ... |
10 |
#include <linux/slab.h> |
51ceddade mac80211: use 4-b... |
11 |
#include <asm/unaligned.h> |
2e3c87368 mac80211: support... |
12 13 |
#include "ieee80211_i.h" #include "mesh.h" |
b8456a14e {nl,cfg,mac}80211... |
14 |
#include "driver-ops.h" |
2e3c87368 mac80211: support... |
15 |
|
bf7cd94dc mac80211: clean u... |
16 |
static int mesh_allocated; |
2e3c87368 mac80211: support... |
17 |
static struct kmem_cache *rm_cache; |
25d49e4d6 mac80211: update ... |
18 19 20 21 22 |
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 ... |
23 |
|
2e3c87368 mac80211: support... |
24 25 |
void ieee80211s_init(void) { |
2e3c87368 mac80211: support... |
26 27 28 29 30 31 32 |
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... |
33 34 |
if (!mesh_allocated) return; |
2e3c87368 mac80211: support... |
35 36 |
kmem_cache_destroy(rm_cache); } |
472dbc45d mac80211: split o... |
37 38 39 40 41 |
static void ieee80211_mesh_housekeeping_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata = (void *) data; struct ieee80211_local *local = sdata->local; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
6b9ac4425 mesh: use set_bit... |
42 |
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
5bb644a0f mac80211: cancel/... |
43 |
|
64592c8fc mac80211: use com... |
44 |
ieee80211_queue_work(&local->hw, &sdata->work); |
472dbc45d mac80211: split o... |
45 |
} |
2e3c87368 mac80211: support... |
46 47 48 |
/** * mesh_matches_local - check if the config of a mesh point matches ours * |
f698d856f replace net_devic... |
49 |
* @sdata: local mesh subif |
f743ff490 mac80211: refacto... |
50 |
* @ie: information elements of a management frame from the mesh peer |
2e3c87368 mac80211: support... |
51 52 53 54 |
* * 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... |
55 56 |
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *ie) |
2e3c87368 mac80211: support... |
57 |
{ |
472dbc45d mac80211: split o... |
58 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
f743ff490 mac80211: refacto... |
59 |
u32 basic_rates = 0; |
4bf88530b mac80211: convert... |
60 |
struct cfg80211_chan_def sta_chan_def; |
21a8e9dd5 mac80211: Fix pos... |
61 |
struct ieee80211_supported_band *sband; |
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 94 |
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); ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def); |
c85fb53c4 mac80211: impleme... |
95 |
|
4bf88530b mac80211: convert... |
96 97 |
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, &sta_chan_def)) |
bf7cd94dc mac80211: clean u... |
98 |
return false; |
2e3c87368 mac80211: support... |
99 |
|
739522baa mac80211: set HT ... |
100 |
return true; |
2e3c87368 mac80211: support... |
101 102 103 104 105 106 |
} /** * 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... |
107 |
*/ |
f698d856f replace net_devic... |
108 |
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
2e3c87368 mac80211: support... |
109 |
{ |
136cfa286 mac80211: use a s... |
110 |
return (ie->mesh_config->meshconf_cap & |
bf7cd94dc mac80211: clean u... |
111 |
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; |
2e3c87368 mac80211: support... |
112 113 114 |
} /** |
2c53040f0 net: Fix (nearly-... |
115 |
* mesh_accept_plinks_update - update accepting_plink in local mesh beacons |
2e3c87368 mac80211: support... |
116 |
* |
d0709a651 mac80211: RCU-ify... |
117 |
* @sdata: mesh interface in which mesh beacons are going to be updated |
df3238189 mac80211: fix unn... |
118 119 |
* * Returns: beacon changed flag if the beacon content changed. |
2e3c87368 mac80211: support... |
120 |
*/ |
df3238189 mac80211: fix unn... |
121 |
u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
122 |
{ |
2e3c87368 mac80211: support... |
123 |
bool free_plinks; |
df3238189 mac80211: fix unn... |
124 |
u32 changed = 0; |
2e3c87368 mac80211: support... |
125 126 127 |
/* 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... |
128 129 130 |
* 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... |
131 132 |
*/ free_plinks = mesh_plink_availables(sdata); |
df3238189 mac80211: fix unn... |
133 134 135 136 137 138 |
if (free_plinks != sdata->u.mesh.accepting_plinks) { sdata->u.mesh.accepting_plinks = free_plinks; changed = BSS_CHANGED_BEACON; } return changed; |
2e3c87368 mac80211: support... |
139 |
} |
45b5028e8 mac80211: fix mes... |
140 141 142 143 144 145 146 147 |
/* * 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... |
148 |
u32 changed = mesh_plink_deactivate(sta); |
fe7a7c576 mac80211: mesh: f... |
149 |
|
f81a9deda mac80211: update ... |
150 |
if (changed) |
2b5e19677 mac80211: cache m... |
151 |
ieee80211_mbss_info_change_notify(sdata, changed); |
45b5028e8 mac80211: fix mes... |
152 |
} |
f698d856f replace net_devic... |
153 |
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
154 |
{ |
2e3c87368 mac80211: support... |
155 |
int i; |
472dbc45d mac80211: split o... |
156 157 |
sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); if (!sdata->u.mesh.rmc) |
2e3c87368 mac80211: support... |
158 |
return -ENOMEM; |
472dbc45d mac80211: split o... |
159 |
sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; |
2e3c87368 mac80211: support... |
160 |
for (i = 0; i < RMC_BUCKETS; i++) |
47a0489ce mac80211: mesh: u... |
161 |
INIT_HLIST_HEAD(&sdata->u.mesh.rmc->bucket[i]); |
2e3c87368 mac80211: support... |
162 163 |
return 0; } |
f698d856f replace net_devic... |
164 |
void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) |
2e3c87368 mac80211: support... |
165 |
{ |
472dbc45d mac80211: split o... |
166 |
struct mesh_rmc *rmc = sdata->u.mesh.rmc; |
47a0489ce mac80211: mesh: u... |
167 168 |
struct rmc_entry *p; struct hlist_node *n; |
2e3c87368 mac80211: support... |
169 |
int i; |
472dbc45d mac80211: split o... |
170 |
if (!sdata->u.mesh.rmc) |
2e3c87368 mac80211: support... |
171 |
return; |
bf7cd94dc mac80211: clean u... |
172 |
for (i = 0; i < RMC_BUCKETS; i++) { |
47a0489ce mac80211: mesh: u... |
173 174 |
hlist_for_each_entry_safe(p, n, &rmc->bucket[i], list) { hlist_del(&p->list); |
2e3c87368 mac80211: support... |
175 176 |
kmem_cache_free(rm_cache, p); } |
bf7cd94dc mac80211: clean u... |
177 |
} |
2e3c87368 mac80211: support... |
178 179 |
kfree(rmc); |
472dbc45d mac80211: split o... |
180 |
sdata->u.mesh.rmc = NULL; |
2e3c87368 mac80211: support... |
181 182 183 184 185 |
} /** * mesh_rmc_check - Check frame in recent multicast cache and add if absent. * |
bf7cd94dc mac80211: clean u... |
186 |
* @sdata: interface |
2e3c87368 mac80211: support... |
187 188 189 190 191 192 193 194 195 |
* @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... |
196 197 |
int mesh_rmc_check(struct ieee80211_sub_if_data *sdata, const u8 *sa, struct ieee80211s_hdr *mesh_hdr) |
2e3c87368 mac80211: support... |
198 |
{ |
472dbc45d mac80211: split o... |
199 |
struct mesh_rmc *rmc = sdata->u.mesh.rmc; |
2e3c87368 mac80211: support... |
200 201 202 |
u32 seqnum = 0; int entries = 0; u8 idx; |
47a0489ce mac80211: mesh: u... |
203 204 |
struct rmc_entry *p; struct hlist_node *n; |
2e3c87368 mac80211: support... |
205 |
|
0aa7fabbd mac80211: mesh: h... |
206 207 |
if (!rmc) return -1; |
2e3c87368 mac80211: support... |
208 |
/* Don't care about endianness since only match matters */ |
51ceddade mac80211: use 4-b... |
209 210 |
memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask; |
47a0489ce mac80211: mesh: u... |
211 |
hlist_for_each_entry_safe(p, n, &rmc->bucket[idx], list) { |
2e3c87368 mac80211: support... |
212 213 |
++entries; if (time_after(jiffies, p->exp_time) || |
bf7cd94dc mac80211: clean u... |
214 |
entries == RMC_QUEUE_MAX_LEN) { |
47a0489ce mac80211: mesh: u... |
215 |
hlist_del(&p->list); |
2e3c87368 mac80211: support... |
216 217 |
kmem_cache_free(rm_cache, p); --entries; |
bf7cd94dc mac80211: clean u... |
218 |
} else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa)) |
2e3c87368 mac80211: support... |
219 220 221 222 |
return -1; } p = kmem_cache_alloc(rm_cache, GFP_ATOMIC); |
d15b84590 mac80211: Remove ... |
223 |
if (!p) |
2e3c87368 mac80211: support... |
224 |
return 0; |
d15b84590 mac80211: Remove ... |
225 |
|
2e3c87368 mac80211: support... |
226 227 228 |
p->seqnum = seqnum; p->exp_time = jiffies + RMC_TIMEOUT; memcpy(p->sa, sa, ETH_ALEN); |
47a0489ce mac80211: mesh: u... |
229 |
hlist_add_head(&p->list, &rmc->bucket[idx]); |
2e3c87368 mac80211: support... |
230 231 |
return 0; } |
bf7cd94dc mac80211: clean u... |
232 233 |
int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
234 235 236 237 238 239 240 241 242 243 244 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u8 *pos, neighbors; u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie); 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 ... |
245 246 |
/* save a pointer for quick updates in pre-tbtt */ ifmsh->meshconf_offset = pos - skb->data; |
082ebb0c2 mac80211: fix mes... |
247 248 249 250 251 252 253 254 255 256 257 |
/* 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... |
258 |
neighbors = atomic_read(&ifmsh->estab_plinks); |
e05ecccdf mac80211: set mes... |
259 |
neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS); |
082ebb0c2 mac80211: fix mes... |
260 261 |
*pos++ = neighbors << 1; /* Mesh capability */ |
b60e527a7 mac80211: set for... |
262 263 264 |
*pos = 0x00; *pos |= ifmsh->mshcfg.dot11MeshForwarding ? IEEE80211_MESHCONF_CAPAB_FORWARDING : 0x00; |
dbf498fba mac80211: Impleme... |
265 |
*pos |= ifmsh->accepting_plinks ? |
bf7cd94dc mac80211: clean u... |
266 |
IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
3f52b7e32 mac80211: mesh po... |
267 268 |
/* Mesh PS mode. See IEEE802.11-2012 8.4.2.100.8 */ *pos |= ifmsh->ps_peers_deep_sleep ? |
bf7cd94dc mac80211: clean u... |
269 |
IEEE80211_MESHCONF_CAPAB_POWER_SAVE_LEVEL : 0x00; |
082ebb0c2 mac80211: fix mes... |
270 271 |
return 0; } |
bf7cd94dc mac80211: clean u... |
272 |
int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
{ 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... |
288 289 |
static int mesh_add_awake_window_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
3f52b7e32 mac80211: mesh po... |
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
{ 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... |
310 311 |
int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
312 313 314 315 316 317 318 319 320 321 |
{ 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... |
322 |
if (offset < ifmsh->ie_len) { |
082ebb0c2 mac80211: fix mes... |
323 324 325 326 |
len = ifmsh->ie_len - offset; data = ifmsh->ie + offset; if (skb_tailroom(skb) < len) return -ENOMEM; |
59ae1d127 networking: intro... |
327 |
skb_put_data(skb, data, len); |
082ebb0c2 mac80211: fix mes... |
328 329 330 331 |
} return 0; } |
bf7cd94dc mac80211: clean u... |
332 |
int mesh_add_rsn_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
333 334 335 336 337 338 339 340 341 |
{ 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... |
342 343 344 |
data = cfg80211_find_ie(WLAN_EID_RSN, ifmsh->ie, ifmsh->ie_len); if (!data) return 0; |
082ebb0c2 mac80211: fix mes... |
345 |
|
a40a8c17b mac80211: fix mes... |
346 347 348 349 |
len = data[1] + 2; if (skb_tailroom(skb) < len) return -ENOMEM; |
59ae1d127 networking: intro... |
350 |
skb_put_data(skb, data, len); |
082ebb0c2 mac80211: fix mes... |
351 352 353 |
return 0; } |
bf7cd94dc mac80211: clean u... |
354 355 |
static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
082ebb0c2 mac80211: fix mes... |
356 |
{ |
55de908ab mac80211: use cha... |
357 358 |
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *chan; |
082ebb0c2 mac80211: fix mes... |
359 |
u8 *pos; |
2e3c87368 mac80211: support... |
360 |
|
082ebb0c2 mac80211: fix mes... |
361 362 |
if (skb_tailroom(skb) < 3) return -ENOMEM; |
55de908ab mac80211: use cha... |
363 364 365 366 367 368 |
rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; } |
4bf88530b mac80211: convert... |
369 |
chan = chanctx_conf->def.chan; |
55de908ab mac80211: use cha... |
370 |
rcu_read_unlock(); |
601513aa2 mac80211: Add the... |
371 372 373 374 |
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... |
375 |
|
082ebb0c2 mac80211: fix mes... |
376 |
return 0; |
2e3c87368 mac80211: support... |
377 |
} |
bf7cd94dc mac80211: clean u... |
378 379 |
int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
176f36086 mac80211: add HT ... |
380 |
{ |
176f36086 mac80211: add HT ... |
381 382 |
struct ieee80211_supported_band *sband; u8 *pos; |
21a8e9dd5 mac80211: Fix pos... |
383 384 385 |
sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; |
176f36086 mac80211: add HT ... |
386 |
if (!sband->ht_cap.ht_supported || |
0418a4458 mac80211: fix var... |
387 388 389 |
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 ... |
390 391 392 393 394 395 |
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... |
396 |
ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); |
176f36086 mac80211: add HT ... |
397 398 399 |
return 0; } |
bf7cd94dc mac80211: clean u... |
400 401 |
int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
176f36086 mac80211: add HT ... |
402 403 |
{ struct ieee80211_local *local = sdata->local; |
55de908ab mac80211: use cha... |
404 405 |
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *channel; |
55de908ab mac80211: use cha... |
406 407 |
struct ieee80211_supported_band *sband; struct ieee80211_sta_ht_cap *ht_cap; |
176f36086 mac80211: add HT ... |
408 |
u8 *pos; |
55de908ab mac80211: use cha... |
409 410 411 412 413 414 |
rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (WARN_ON(!chanctx_conf)) { rcu_read_unlock(); return -EINVAL; } |
4bf88530b mac80211: convert... |
415 |
channel = chanctx_conf->def.chan; |
55de908ab mac80211: use cha... |
416 417 418 419 |
rcu_read_unlock(); sband = local->hw.wiphy->bands[channel->band]; ht_cap = &sband->ht_cap; |
c85fb53c4 mac80211: impleme... |
420 421 422 423 |
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 ... |
424 |
return 0; |
074d46d1d wireless: rename ... |
425 |
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation)) |
176f36086 mac80211: add HT ... |
426 |
return -ENOMEM; |
074d46d1d wireless: rename ... |
427 |
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); |
4bf88530b mac80211: convert... |
428 |
ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef, |
57f255f58 mac80211: TDLS: a... |
429 430 |
sdata->vif.bss_conf.ht_operation_mode, false); |
176f36086 mac80211: add HT ... |
431 432 433 |
return 0; } |
bf7cd94dc mac80211: clean u... |
434 |
|
c85fb53c4 mac80211: impleme... |
435 436 437 |
int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { |
c85fb53c4 mac80211: impleme... |
438 439 |
struct ieee80211_supported_band *sband; u8 *pos; |
21a8e9dd5 mac80211: Fix pos... |
440 441 442 |
sband = ieee80211_get_sband(sdata); if (!sband) return -EINVAL; |
c85fb53c4 mac80211: impleme... |
443 444 445 446 447 448 449 450 451 452 453 454 455 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 483 484 485 486 487 488 489 490 491 492 493 494 |
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; 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; } |
2e3c87368 mac80211: support... |
495 496 497 498 |
static void ieee80211_mesh_path_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata = (struct ieee80211_sub_if_data *) data; |
5bb644a0f mac80211: cancel/... |
499 |
|
690205f18 mac80211: cleanup... |
500 |
ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
2e3c87368 mac80211: support... |
501 |
} |
e304bfd30 mac80211: impleme... |
502 503 504 505 506 |
static void ieee80211_mesh_path_root_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata = (struct ieee80211_sub_if_data *) data; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
e304bfd30 mac80211: impleme... |
507 508 |
set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); |
690205f18 mac80211: cleanup... |
509 |
ieee80211_queue_work(&sdata->local->hw, &sdata->work); |
e304bfd30 mac80211: impleme... |
510 |
} |
63c5723bc mac80211: add nl8... |
511 512 |
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) { |
dbb912cd4 mac80211: invoke ... |
513 |
if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT) |
63c5723bc mac80211: add nl8... |
514 515 516 517 518 519 520 |
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... |
521 |
/** |
3c5772a52 mac80211: Use 3-a... |
522 |
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame |
bf7cd94dc mac80211: clean u... |
523 |
* @hdr: 802.11 frame header |
3c5772a52 mac80211: Use 3-a... |
524 525 526 527 528 529 530 |
* @fc: frame control field * @meshda: destination address in the mesh * @meshsa: source address address in the mesh. Same as TA, as frame is * locally originated. * * Return the length of the 802.11 (does not include a mesh control header) */ |
15ff63653 mac80211: use fix... |
531 532 533 |
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, const u8 *meshda, const u8 *meshsa) { |
3c5772a52 mac80211: Use 3-a... |
534 535 536 537 538 539 540 541 |
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... |
542 |
*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
3c5772a52 mac80211: Use 3-a... |
543 |
/* RA TA DA SA */ |
c84a67a2f mac80211: Use eth... |
544 |
eth_zero_addr(hdr->addr1); /* RA is resolved later */ |
3c5772a52 mac80211: Use 3-a... |
545 546 547 548 549 550 551 552 |
memcpy(hdr->addr2, meshsa, ETH_ALEN); memcpy(hdr->addr3, meshda, ETH_ALEN); memcpy(hdr->addr4, meshsa, ETH_ALEN); return 30; } } /** |
902acc789 mac80211: clean u... |
553 |
* ieee80211_new_mesh_header - create a new mesh header |
902acc789 mac80211: clean u... |
554 |
* @sdata: mesh interface to be used |
bf7cd94dc mac80211: clean u... |
555 |
* @meshhdr: uninitialized mesh header |
61ad53945 mac80211: Remove ... |
556 557 558 559 560 |
* @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... |
561 562 563 |
* * Return the header length. */ |
5edfcee5e mac80211: make ie... |
564 565 566 |
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... |
567 |
{ |
bf7cd94dc mac80211: clean u... |
568 569 |
if (WARN_ON(!addr4or5 && addr6)) return 0; |
0c3cee72a net/mac80211: Cor... |
570 |
memset(meshhdr, 0, sizeof(*meshhdr)); |
bf7cd94dc mac80211: clean u... |
571 |
|
472dbc45d mac80211: split o... |
572 |
meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
bf7cd94dc mac80211: clean u... |
573 574 |
/* FIXME: racy -- TX on multiple queues can be concurrent */ |
472dbc45d mac80211: split o... |
575 576 |
put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); sdata->u.mesh.mesh_seqnum++; |
bf7cd94dc mac80211: clean u... |
577 |
|
61ad53945 mac80211: Remove ... |
578 |
if (addr4or5 && !addr6) { |
3c5772a52 mac80211: Use 3-a... |
579 |
meshhdr->flags |= MESH_FLAGS_AE_A4; |
61ad53945 mac80211: Remove ... |
580 |
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); |
bf7cd94dc mac80211: clean u... |
581 |
return 2 * ETH_ALEN; |
61ad53945 mac80211: Remove ... |
582 |
} else if (addr4or5 && addr6) { |
3c5772a52 mac80211: Use 3-a... |
583 |
meshhdr->flags |= MESH_FLAGS_AE_A5_A6; |
61ad53945 mac80211: Remove ... |
584 585 |
memcpy(meshhdr->eaddr1, addr4or5, ETH_ALEN); memcpy(meshhdr->eaddr2, addr6, ETH_ALEN); |
bf7cd94dc mac80211: clean u... |
586 |
return 3 * ETH_ALEN; |
3c5772a52 mac80211: Use 3-a... |
587 |
} |
bf7cd94dc mac80211: clean u... |
588 589 |
return ETH_ALEN; |
902acc789 mac80211: clean u... |
590 |
} |
bf7cd94dc mac80211: clean u... |
591 |
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) |
472dbc45d mac80211: split o... |
592 |
{ |
bf7cd94dc mac80211: clean u... |
593 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
df3238189 mac80211: fix unn... |
594 |
u32 changed; |
472dbc45d mac80211: split o... |
595 |
|
31f909a2c nl/mac80211: allo... |
596 597 |
if (ifmsh->mshcfg.plink_timeout > 0) ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ); |
472dbc45d mac80211: split o... |
598 |
mesh_path_expire(sdata); |
df3238189 mac80211: fix unn... |
599 |
changed = mesh_accept_plinks_update(sdata); |
2b5e19677 mac80211: cache m... |
600 |
ieee80211_mbss_info_change_notify(sdata, changed); |
472dbc45d mac80211: split o... |
601 |
|
472dbc45d mac80211: split o... |
602 |
mod_timer(&ifmsh->housekeeping_timer, |
bf7cd94dc mac80211: clean u... |
603 604 |
round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
472dbc45d mac80211: split o... |
605 |
} |
e304bfd30 mac80211: impleme... |
606 607 608 |
static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
a69cc44fe mac80211: impleme... |
609 |
u32 interval; |
e304bfd30 mac80211: impleme... |
610 611 |
mesh_path_tx_root_frame(sdata); |
a69cc44fe mac80211: impleme... |
612 613 614 615 616 |
if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN) interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; else interval = ifmsh->mshcfg.dot11MeshHWMProotInterval; |
e304bfd30 mac80211: impleme... |
617 |
mod_timer(&ifmsh->mesh_path_root_timer, |
a69cc44fe mac80211: impleme... |
618 |
round_jiffies(TU_TO_EXP_TIME(interval))); |
e304bfd30 mac80211: impleme... |
619 |
} |
2b5e19677 mac80211: cache m... |
620 621 622 623 624 625 626 627 |
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... |
628 |
struct mesh_csa_settings *csa; |
57fbcce37 cfg80211: remove ... |
629 |
enum nl80211_band band; |
2b5e19677 mac80211: cache m... |
630 631 632 633 634 635 636 637 638 639 640 641 642 |
u8 *pos; struct ieee80211_sub_if_data *sdata; int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + sizeof(mgmt->u.beacon); 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(); head_len = hdr_len + 2 + /* NULL SSID */ |
b8456a14e {nl,cfg,mac}80211... |
643 644 |
/* Channel Switch Announcement */ 2 + sizeof(struct ieee80211_channel_sw_ie) + |
08a7e621f scripts/spelling.... |
645 |
/* Mesh Channel Switch Parameters */ |
b8456a14e {nl,cfg,mac}80211... |
646 |
2 + sizeof(struct ieee80211_mesh_chansw_params_ie) + |
75d627d53 mac80211: mesh: s... |
647 648 649 |
/* 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... |
650 651 652 653 654 655 656 657 |
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... |
658 659 |
2 + sizeof(struct ieee80211_vht_cap) + 2 + sizeof(struct ieee80211_vht_operation) + |
2b5e19677 mac80211: cache m... |
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 |
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... |
676 |
mgmt = skb_put_zero(skb, hdr_len); |
2b5e19677 mac80211: cache m... |
677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
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... |
691 692 693 |
rcu_read_lock(); csa = rcu_dereference(ifmsh->csa); if (csa) { |
75d627d53 mac80211: mesh: s... |
694 695 696 697 |
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: ... |
698 |
pos = skb_put_zero(skb, ie_len); |
b8456a14e {nl,cfg,mac}80211... |
699 700 701 702 703 |
*pos++ = WLAN_EID_CHANNEL_SWITCH; *pos++ = 3; *pos++ = 0x0; *pos++ = ieee80211_frequency_to_channel( csa->settings.chandef.chan->center_freq); |
8df734e86 mac80211: fix the... |
704 |
bcn->csa_current_counter = csa->settings.count; |
af296bdb8 mac80211: move cs... |
705 |
bcn->csa_counter_offsets[0] = hdr_len + 6; |
b8456a14e {nl,cfg,mac}80211... |
706 707 708 |
*pos++ = csa->settings.count; *pos++ = WLAN_EID_CHAN_SWITCH_PARAM; *pos++ = 6; |
0cb4d4dce mac80211: refacto... |
709 |
if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) { |
b8456a14e {nl,cfg,mac}80211... |
710 711 712 713 714 715 716 717 718 |
*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... |
719 |
put_unaligned_le16(ifmsh->pre_value, pos); |
b8456a14e {nl,cfg,mac}80211... |
720 |
pos += 2; |
75d627d53 mac80211: mesh: s... |
721 722 723 724 |
switch (csa->settings.chandef.width) { case NL80211_CHAN_WIDTH_40: ie_len = 2 + sizeof(struct ieee80211_sec_chan_offs_ie); |
e45a79da8 skbuff/mac80211: ... |
725 |
pos = skb_put_zero(skb, ie_len); |
75d627d53 mac80211: mesh: s... |
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
*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: ... |
741 |
pos = skb_put_zero(skb, ie_len); |
75d627d53 mac80211: mesh: s... |
742 743 744 745 746 747 748 749 750 751 |
*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... |
752 753 |
} rcu_read_unlock(); |
2b5e19677 mac80211: cache m... |
754 |
if (ieee80211_add_srates_ie(sdata, skb, true, band) || |
bf7cd94dc mac80211: clean u... |
755 |
mesh_add_ds_params_ie(sdata, skb)) |
2b5e19677 mac80211: cache m... |
756 757 758 759 760 761 762 763 764 765 |
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... |
766 767 768 769 770 771 |
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... |
772 773 |
mesh_add_vht_cap_ie(sdata, skb) || mesh_add_vht_oper_ie(sdata, skb) || |
bf7cd94dc mac80211: clean u... |
774 |
mesh_add_vendor_ies(sdata, skb)) |
2b5e19677 mac80211: cache m... |
775 776 777 778 |
goto out_free; bcn->tail_len = skb->len; memcpy(bcn->tail, skb->data, bcn->tail_len); |
43552be1d mac80211: update ... |
779 780 |
bcn->meshconf = (struct ieee80211_meshconf_ie *) (bcn->tail + ifmsh->meshconf_offset); |
2b5e19677 mac80211: cache m... |
781 782 783 784 785 786 787 788 789 790 791 |
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... |
792 |
ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata) |
2b5e19677 mac80211: cache m... |
793 |
{ |
2b5e19677 mac80211: cache m... |
794 795 |
struct beacon_data *old_bcn; int ret; |
2b5e19677 mac80211: cache m... |
796 |
|
8d61ffa5e cfg80211/mac80211... |
797 798 799 |
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... |
800 801 |
if (ret) /* just reuse old beacon */ |
8d61ffa5e cfg80211/mac80211... |
802 |
return ret; |
2b5e19677 mac80211: cache m... |
803 804 805 |
if (old_bcn) kfree_rcu(old_bcn, rcu_head); |
8d61ffa5e cfg80211/mac80211... |
806 |
return 0; |
2b5e19677 mac80211: cache m... |
807 808 809 810 811 |
} void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed) { |
f81a9deda mac80211: update ... |
812 813 814 815 816 817 818 819 820 821 822 823 |
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... |
824 825 826 |
} int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) |
472dbc45d mac80211: split o... |
827 828 829 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; |
f4eabc918 mac80211: use sho... |
830 831 832 833 834 |
u32 changed = BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_HT | BSS_CHANGED_BASIC_RATES | BSS_CHANGED_BEACON_INT; |
472dbc45d mac80211: split o... |
835 |
|
09b174702 mac80211: move me... |
836 837 838 839 |
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... |
840 |
ifmsh->mesh_cc_id = 0; /* Disabled */ |
dbf498fba mac80211: Impleme... |
841 842 |
/* register sync ops from extensible synchronization framework */ ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id); |
dbf498fba mac80211: Impleme... |
843 |
ifmsh->sync_offset_clockdrift_max = 0; |
6b9ac4425 mesh: use set_bit... |
844 |
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
63c5723bc mac80211: add nl8... |
845 |
ieee80211_mesh_root_setup(ifmsh); |
64592c8fc mac80211: use com... |
846 |
ieee80211_queue_work(&local->hw, &sdata->work); |
70c33eaae {nl,cfg,mac}80211... |
847 848 |
sdata->vif.bss_conf.ht_operation_mode = ifmsh->mshcfg.ht_opmode; |
d6a832288 mac80211: track e... |
849 |
sdata->vif.bss_conf.enable_beacon = true; |
f4eabc918 mac80211: use sho... |
850 |
|
39886b618 mac80211: consoli... |
851 |
changed |= ieee80211_mps_local_status_update(sdata); |
3f52b7e32 mac80211: mesh po... |
852 |
|
2b5e19677 mac80211: cache m... |
853 854 855 856 |
if (ieee80211_mesh_build_beacon(ifmsh)) { ieee80211_stop_mesh(sdata); return -ENOMEM; } |
057d5f4ba mac80211: sync dt... |
857 |
ieee80211_recalc_dtim(local, sdata); |
f4eabc918 mac80211: use sho... |
858 |
ieee80211_bss_info_change_notify(sdata, changed); |
c405c6298 mac80211: manage ... |
859 860 |
netif_carrier_on(sdata->dev); |
2b5e19677 mac80211: cache m... |
861 |
return 0; |
472dbc45d mac80211: split o... |
862 863 864 865 |
} void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) { |
09b174702 mac80211: move me... |
866 |
struct ieee80211_local *local = sdata->local; |
29cbe68c5 cfg80211/mac80211... |
867 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
2b5e19677 mac80211: cache m... |
868 |
struct beacon_data *bcn; |
29cbe68c5 cfg80211/mac80211... |
869 |
|
c405c6298 mac80211: manage ... |
870 |
netif_carrier_off(sdata->dev); |
c37a54ac3 mac80211: mesh: f... |
871 872 873 |
/* flush STAs and mpaths on this iface */ sta_info_flush(sdata); mesh_path_flush_by_iface(sdata); |
0d466b9c6 mac80211: improve... |
874 |
/* stop the beacon */ |
29cbe68c5 cfg80211/mac80211... |
875 |
ifmsh->mesh_id_len = 0; |
d6a832288 mac80211: track e... |
876 877 |
sdata->vif.bss_conf.enable_beacon = false; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
29cbe68c5 cfg80211/mac80211... |
878 |
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
c37a54ac3 mac80211: mesh: f... |
879 880 |
/* remove beacon */ |
2b5e19677 mac80211: cache m... |
881 |
bcn = rcu_dereference_protected(ifmsh->beacon, |
8d61ffa5e cfg80211/mac80211... |
882 |
lockdep_is_held(&sdata->wdev.mtx)); |
0c2bef462 mac80211: use RCU... |
883 |
RCU_INIT_POINTER(ifmsh->beacon, NULL); |
2b5e19677 mac80211: cache m... |
884 |
kfree_rcu(bcn, rcu_head); |
0d466b9c6 mac80211: improve... |
885 |
|
3f52b7e32 mac80211: mesh po... |
886 887 888 |
/* 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... |
889 |
del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
e304bfd30 mac80211: impleme... |
890 |
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); |
dd4c9260e mac80211: cancel ... |
891 |
del_timer_sync(&sdata->u.mesh.mesh_path_timer); |
09b174702 mac80211: move me... |
892 |
|
f81a9deda mac80211: update ... |
893 894 895 |
/* clear any mesh work (for next join) we may have accrued */ ifmsh->wrkq_flags = 0; ifmsh->mbss_changed = 0; |
09b174702 mac80211: move me... |
896 897 898 |
local->fif_other_bss--; atomic_dec(&local->iff_allmultis); ieee80211_configure_filter(local); |
472dbc45d mac80211: split o... |
899 |
} |
5d55371b2 mac80211: mesh: m... |
900 901 902 903 904 905 906 907 908 909 910 911 912 913 |
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... |
914 915 916 917 918 919 |
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... |
920 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
21a8e9dd5 mac80211: Fix pos... |
921 |
struct ieee80211_supported_band *sband; |
0cb4d4dce mac80211: refacto... |
922 |
int err; |
33a45867c mac80211: process... |
923 |
u32 sta_flags; |
dbd72850d mac80211: add mis... |
924 |
sdata_assert_lock(sdata); |
21a8e9dd5 mac80211: Fix pos... |
925 926 927 |
sband = ieee80211_get_sband(sdata); if (!sband) return false; |
71ec289e6 mac80211: enable ... |
928 |
sta_flags = 0; |
33a45867c mac80211: process... |
929 930 931 932 933 |
switch (sdata->vif.bss_conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: sta_flags |= IEEE80211_STA_DISABLE_HT; case NL80211_CHAN_WIDTH_20: sta_flags |= IEEE80211_STA_DISABLE_40MHZ; |
71ec289e6 mac80211: enable ... |
934 935 |
case NL80211_CHAN_WIDTH_40: sta_flags |= IEEE80211_STA_DISABLE_VHT; |
33a45867c mac80211: process... |
936 937 938 939 940 941 |
break; default: break; } memset(¶ms, 0, sizeof(params)); |
21a8e9dd5 mac80211: Fix pos... |
942 |
err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band, |
33a45867c mac80211: process... |
943 944 945 946 947 948 |
sta_flags, sdata->vif.addr, &csa_ie); if (err < 0) return false; if (err) return false; |
5d55371b2 mac80211: mesh: m... |
949 950 951 952 953 |
/* 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... |
954 955 |
params.chandef = csa_ie.chandef; params.count = csa_ie.count; |
33a45867c mac80211: process... |
956 |
if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, |
0ab2e55d3 mac80211: mesh: A... |
957 958 959 |
IEEE80211_CHAN_DISABLED) || !cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef, NL80211_IFTYPE_MESH_POINT)) { |
33a45867c mac80211: process... |
960 961 962 963 964 965 966 967 968 969 970 971 |
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... |
972 973 |
¶ms.chandef, NL80211_IFTYPE_MESH_POINT); |
33a45867c mac80211: process... |
974 975 |
if (err < 0) return false; |
0ab2e55d3 mac80211: mesh: A... |
976 977 978 979 980 981 982 983 984 |
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... |
985 |
return false; |
0ab2e55d3 mac80211: mesh: A... |
986 |
} |
2beb6dab2 cfg80211/mac80211... |
987 988 |
params.radar_required = err; |
33a45867c mac80211: process... |
989 |
|
0cb4d4dce mac80211: refacto... |
990 991 992 993 994 995 996 |
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... |
997 998 999 1000 1001 1002 1003 |
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... |
1004 |
if (beacon) { |
33a45867c mac80211: process... |
1005 |
ifmsh->chsw_ttl = csa_ie.ttl - 1; |
3f718fd84 mac80211: fix the... |
1006 1007 1008 1009 |
if (ifmsh->pre_value >= csa_ie.pre_value) return false; ifmsh->pre_value = csa_ie.pre_value; } |
33a45867c mac80211: process... |
1010 |
|
0cb4d4dce mac80211: refacto... |
1011 |
if (ifmsh->chsw_ttl >= ifmsh->mshcfg.dot11MeshTTL) |
3f718fd84 mac80211: fix the... |
1012 |
return false; |
33a45867c mac80211: process... |
1013 |
|
0cb4d4dce mac80211: refacto... |
1014 |
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_REPEATER; |
33a45867c mac80211: process... |
1015 |
|
0cb4d4dce mac80211: refacto... |
1016 1017 1018 |
if (ieee80211_channel_switch(sdata->local->hw.wiphy, sdata->dev, ¶ms) < 0) return false; |
33a45867c mac80211: process... |
1019 1020 |
return true; |
33a45867c mac80211: process... |
1021 |
} |
9fb04b501 mac80211: generat... |
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 |
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 ... |
1033 |
u8 *pos; |
9fb04b501 mac80211: generat... |
1034 |
|
9fb04b501 mac80211: generat... |
1035 1036 1037 1038 |
pos = mgmt->u.probe_req.variable; baselen = (u8 *) pos - (u8 *) mgmt; if (baselen > len) return; |
b2e506bfc mac80211: parse V... |
1039 |
ieee802_11_parse_elems(pos, len - baselen, false, &elems); |
9fb04b501 mac80211: generat... |
1040 |
|
a4ef66a91 mac80211: only re... |
1041 1042 |
if (!elems.mesh_id) return; |
9fb04b501 mac80211: generat... |
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
/* 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... |
1066 1067 |
skb_put_data(presp, bcn->head, bcn->head_len); skb_put_data(presp, bcn->tail, bcn->tail_len); |
9fb04b501 mac80211: generat... |
1068 1069 1070 1071 |
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... |
1072 1073 1074 1075 1076 |
IEEE80211_SKB_CB(presp)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, presp); out: rcu_read_unlock(); } |
472dbc45d mac80211: split o... |
1077 1078 1079 1080 1081 1082 |
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... |
1083 |
struct ieee80211_local *local = sdata->local; |
dbf498fba mac80211: Impleme... |
1084 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
472dbc45d mac80211: split o... |
1085 1086 |
struct ieee802_11_elems elems; struct ieee80211_channel *channel; |
472dbc45d mac80211: split o... |
1087 1088 |
size_t baselen; int freq; |
57fbcce37 cfg80211: remove ... |
1089 |
enum nl80211_band band = rx_status->band; |
472dbc45d mac80211: split o... |
1090 1091 1092 |
/* ignore ProbeResp to foreign address */ if (stype == IEEE80211_STYPE_PROBE_RESP && |
b203ca391 mac80211: Convert... |
1093 |
!ether_addr_equal(mgmt->da, sdata->vif.addr)) |
472dbc45d mac80211: split o... |
1094 1095 1096 1097 1098 1099 1100 |
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, |
b2e506bfc mac80211: parse V... |
1101 |
false, &elems); |
472dbc45d mac80211: split o... |
1102 |
|
9a90bc819 mac80211: mesh ST... |
1103 1104 1105 1106 |
/* 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 ... |
1107 |
return; |
1cd8e88e1 mac80211: check D... |
1108 |
if (elems.ds_params) |
59eb21a65 cfg80211: Extend ... |
1109 |
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band); |
472dbc45d mac80211: split o... |
1110 1111 1112 1113 1114 1115 1116 |
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... |
1117 1118 1119 1120 1121 1122 1123 1124 1125 |
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) mesh_neighbour_update(sdata, mgmt->sa, &elems); } |
dbf498fba mac80211: Impleme... |
1126 1127 1128 1129 |
if (ifmsh->sync_ops) ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, &elems, rx_status); |
33a45867c mac80211: process... |
1130 |
|
0cb4d4dce mac80211: refacto... |
1131 1132 |
if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT && !sdata->vif.csa_active) |
33a45867c mac80211: process... |
1133 |
ieee80211_mesh_process_chnswitch(sdata, &elems, true); |
472dbc45d mac80211: split o... |
1134 |
} |
b8456a14e {nl,cfg,mac}80211... |
1135 1136 1137 1138 1139 |
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... |
1140 |
int changed = 0; |
b8456a14e {nl,cfg,mac}80211... |
1141 1142 |
/* Reset the TTL value and Initiator flag */ |
0cb4d4dce mac80211: refacto... |
1143 |
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; |
b8456a14e {nl,cfg,mac}80211... |
1144 1145 1146 1147 |
ifmsh->chsw_ttl = 0; /* Remove the CSA and MCSP elements from the beacon */ tmp_csa_settings = rcu_dereference(ifmsh->csa); |
0c2bef462 mac80211: use RCU... |
1148 |
RCU_INIT_POINTER(ifmsh->csa, NULL); |
66e01cf99 mac80211: only se... |
1149 1150 |
if (tmp_csa_settings) kfree_rcu(tmp_csa_settings, rcu_head); |
b8456a14e {nl,cfg,mac}80211... |
1151 1152 1153 |
ret = ieee80211_mesh_rebuild_beacon(sdata); if (ret) return -EINVAL; |
faf046e72 mac80211: batch C... |
1154 |
changed |= BSS_CHANGED_BEACON; |
b8456a14e {nl,cfg,mac}80211... |
1155 1156 1157 |
mcsa_dbg(sdata, "complete switching to center freq %d MHz", sdata->vif.bss_conf.chandef.chan->center_freq); |
faf046e72 mac80211: batch C... |
1158 |
return changed; |
b8456a14e {nl,cfg,mac}80211... |
1159 1160 1161 |
} int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, |
66e01cf99 mac80211: only se... |
1162 |
struct cfg80211_csa_settings *csa_settings) |
b8456a14e {nl,cfg,mac}80211... |
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 |
{ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_csa_settings *tmp_csa_settings; int ret = 0; 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... |
1181 |
RCU_INIT_POINTER(ifmsh->csa, NULL); |
b8456a14e {nl,cfg,mac}80211... |
1182 1183 1184 |
kfree_rcu(tmp_csa_settings, rcu_head); return ret; } |
b58e81e96 mac80211: align i... |
1185 |
return BSS_CHANGED_BEACON; |
b8456a14e {nl,cfg,mac}80211... |
1186 |
} |
8f2535b92 mac80211: process... |
1187 |
static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, |
0f097096b mac80211: mesh: f... |
1188 1189 |
struct ieee80211_mgmt *mgmt, size_t len, struct ieee802_11_elems *elems) |
8f2535b92 mac80211: process... |
1190 1191 1192 1193 |
{ struct ieee80211_mgmt *mgmt_fwd; struct sk_buff *skb; struct ieee80211_local *local = sdata->local; |
8f2535b92 mac80211: process... |
1194 1195 1196 1197 1198 |
skb = dev_alloc_skb(local->tx_headroom + len); if (!skb) return -ENOMEM; skb_reserve(skb, local->tx_headroom); |
4df864c1d networking: make ... |
1199 |
mgmt_fwd = skb_put(skb, len); |
8f2535b92 mac80211: process... |
1200 |
|
0f097096b mac80211: mesh: f... |
1201 1202 1203 |
elems->mesh_chansw_params_ie->mesh_ttl--; elems->mesh_chansw_params_ie->mesh_flags &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR; |
8f2535b92 mac80211: process... |
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 |
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... |
1220 |
bool fwd_csa = true; |
8f2535b92 mac80211: process... |
1221 |
size_t baselen; |
3f718fd84 mac80211: fix the... |
1222 |
u8 *pos; |
8f2535b92 mac80211: process... |
1223 1224 1225 1226 1227 1228 1229 1230 |
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); |
3b23782f7 mac80211: mark as... |
1231 |
ieee802_11_parse_elems(pos, len - baselen, true, &elems); |
8f2535b92 mac80211: process... |
1232 |
|
3f718fd84 mac80211: fix the... |
1233 1234 |
ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl; if (!--ifmsh->chsw_ttl) |
8f2535b92 mac80211: process... |
1235 1236 1237 1238 1239 1240 1241 |
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... |
1242 1243 |
if (!sdata->vif.csa_active && !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) { |
33a45867c mac80211: process... |
1244 1245 1246 |
mcsa_dbg(sdata, "Failed to process CSA action frame"); return; } |
8f2535b92 mac80211: process... |
1247 1248 |
/* forward or re-broadcast the CSA frame */ if (fwd_csa) { |
0f097096b mac80211: mesh: f... |
1249 |
if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0) |
8f2535b92 mac80211: process... |
1250 1251 |
mcsa_dbg(sdata, "Failed to forward the CSA frame"); } |
8f2535b92 mac80211: process... |
1252 |
} |
472dbc45d mac80211: split o... |
1253 1254 1255 1256 1257 1258 |
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 ... |
1259 1260 1261 1262 1263 1264 1265 1266 |
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... |
1267 |
break; |
25d49e4d6 mac80211: update ... |
1268 1269 1270 |
case WLAN_CATEGORY_MESH_ACTION: if (mesh_action_is_path_sel(mgmt)) mesh_rx_path_sel_frame(sdata, mgmt, len); |
472dbc45d mac80211: split o... |
1271 |
break; |
8f2535b92 mac80211: process... |
1272 1273 1274 |
case WLAN_CATEGORY_SPECTRUM_MGMT: mesh_rx_csa_frame(sdata, mgmt, len); break; |
472dbc45d mac80211: split o... |
1275 1276 |
} } |
1fa57d017 mac80211: use com... |
1277 1278 |
void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
472dbc45d mac80211: split o... |
1279 1280 |
{ struct ieee80211_rx_status *rx_status; |
472dbc45d mac80211: split o... |
1281 1282 |
struct ieee80211_mgmt *mgmt; u16 stype; |
ecccd072b mac80211: fix mes... |
1283 1284 1285 |
sdata_lock(sdata); /* mesh already went down */ |
1693d3441 mac80211: use sda... |
1286 |
if (!sdata->u.mesh.mesh_id_len) |
ecccd072b mac80211: fix mes... |
1287 |
goto out; |
f1d58c252 mac80211: push rx... |
1288 |
rx_status = IEEE80211_SKB_RXCB(skb); |
472dbc45d mac80211: split o... |
1289 1290 1291 1292 1293 1294 1295 1296 1297 |
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... |
1298 1299 1300 |
case IEEE80211_STYPE_PROBE_REQ: ieee80211_mesh_rx_probe_req(sdata, mgmt, skb->len); break; |
472dbc45d mac80211: split o... |
1301 1302 1303 1304 |
case IEEE80211_STYPE_ACTION: ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); break; } |
ecccd072b mac80211: fix mes... |
1305 1306 |
out: sdata_unlock(sdata); |
472dbc45d mac80211: split o... |
1307 |
} |
f81a9deda mac80211: update ... |
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 |
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... |
1329 |
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) |
472dbc45d mac80211: split o... |
1330 |
{ |
472dbc45d mac80211: split o... |
1331 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
472dbc45d mac80211: split o... |
1332 |
|
ecccd072b mac80211: fix mes... |
1333 1334 1335 |
sdata_lock(sdata); /* mesh already went down */ |
1693d3441 mac80211: use sda... |
1336 |
if (!sdata->u.mesh.mesh_id_len) |
ecccd072b mac80211: fix mes... |
1337 |
goto out; |
472dbc45d mac80211: split o... |
1338 1339 1340 1341 |
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... |
1342 |
if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) |
bf7cd94dc mac80211: clean u... |
1343 |
ieee80211_mesh_housekeeping(sdata); |
e304bfd30 mac80211: impleme... |
1344 1345 1346 |
if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) ieee80211_mesh_rootpath(sdata); |
dbf498fba mac80211: Impleme... |
1347 1348 |
if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) |
445cd452f mac80211: Use app... |
1349 |
mesh_sync_adjust_tsf(sdata); |
ecccd072b mac80211: fix mes... |
1350 |
|
f81a9deda mac80211: update ... |
1351 1352 |
if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags)) mesh_bss_info_changed(sdata); |
ecccd072b mac80211: fix mes... |
1353 1354 |
out: sdata_unlock(sdata); |
472dbc45d mac80211: split o... |
1355 |
} |
472dbc45d mac80211: split o... |
1356 |
|
902acc789 mac80211: clean u... |
1357 1358 |
void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) { |
472dbc45d mac80211: split o... |
1359 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
ad2d223aa mac80211: assign ... |
1360 |
static u8 zero_addr[ETH_ALEN] = {}; |
472dbc45d mac80211: split o... |
1361 |
|
472dbc45d mac80211: split o... |
1362 1363 1364 |
setup_timer(&ifmsh->housekeeping_timer, ieee80211_mesh_housekeeping_timer, (unsigned long) sdata); |
472dbc45d mac80211: split o... |
1365 |
|
472dbc45d mac80211: split o... |
1366 |
ifmsh->accepting_plinks = true; |
472dbc45d mac80211: split o... |
1367 |
atomic_set(&ifmsh->mpaths, 0); |
f698d856f replace net_devic... |
1368 |
mesh_rmc_init(sdata); |
472dbc45d mac80211: split o... |
1369 |
ifmsh->last_preq = jiffies; |
dca7e9430 {nl,cfg,mac}80211... |
1370 |
ifmsh->next_perr = jiffies; |
0cb4d4dce mac80211: refacto... |
1371 |
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; |
902acc789 mac80211: clean u... |
1372 1373 1374 |
/* Allocate all mesh structures when creating the first mesh interface. */ if (!mesh_allocated) ieee80211s_init(); |
2bdaf386f mac80211: mesh: m... |
1375 1376 |
mesh_pathtbl_init(sdata); |
472dbc45d mac80211: split o... |
1377 |
setup_timer(&ifmsh->mesh_path_timer, |
902acc789 mac80211: clean u... |
1378 1379 |
ieee80211_mesh_path_timer, (unsigned long) sdata); |
e304bfd30 mac80211: impleme... |
1380 1381 1382 |
setup_timer(&ifmsh->mesh_path_root_timer, ieee80211_mesh_path_root_timer, (unsigned long) sdata); |
472dbc45d mac80211: split o... |
1383 |
INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
3f52b7e32 mac80211: mesh po... |
1384 |
skb_queue_head_init(&ifmsh->ps.bc_buf); |
472dbc45d mac80211: split o... |
1385 |
spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
dbf498fba mac80211: Impleme... |
1386 |
spin_lock_init(&ifmsh->sync_offset_lock); |
2b5e19677 mac80211: cache m... |
1387 |
RCU_INIT_POINTER(ifmsh->beacon, NULL); |
ad2d223aa mac80211: assign ... |
1388 1389 |
sdata->vif.bss_conf.bssid = zero_addr; |
472dbc45d mac80211: split o... |
1390 |
} |
0371a08fb mac80211: mesh: f... |
1391 1392 1393 1394 1395 1396 |
void ieee80211_mesh_teardown_sdata(struct ieee80211_sub_if_data *sdata) { mesh_rmc_free(sdata); mesh_pathtbl_unregister(sdata); } |