Blame view
net/mac80211/mesh_pathtbl.c
29.3 KB
eb2b9311f mac80211: mesh pa... |
1 |
/* |
264d9b7d8 mac80211: update ... |
2 |
* Copyright (c) 2008, 2009 open80211s Ltd. |
eb2b9311f mac80211: mesh pa... |
3 4 5 6 7 8 9 10 11 |
* Author: Luis Carlos Cobo <luisca@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. */ #include <linux/etherdevice.h> #include <linux/list.h> |
eb2b9311f mac80211: mesh pa... |
12 |
#include <linux/random.h> |
5a0e3ad6a include cleanup: ... |
13 |
#include <linux/slab.h> |
eb2b9311f mac80211: mesh pa... |
14 15 16 |
#include <linux/spinlock.h> #include <linux/string.h> #include <net/mac80211.h> |
4777be416 mac80211: Start i... |
17 |
#include "wme.h" |
eb2b9311f mac80211: mesh pa... |
18 19 20 21 22 23 24 25 |
#include "ieee80211_i.h" #include "mesh.h" /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */ #define INIT_PATHS_SIZE_ORDER 2 /* Keep the mean chain length below this constant */ #define MEAN_CHAIN_LEN 2 |
bf7cd94dc mac80211: clean u... |
26 27 28 29 30 31 |
static inline bool mpath_expired(struct mesh_path *mpath) { return (mpath->flags & MESH_PATH_ACTIVE) && time_after(jiffies, mpath->exp_time) && !(mpath->flags & MESH_PATH_FIXED); } |
eb2b9311f mac80211: mesh pa... |
32 33 34 35 36 37 38 39 40 |
struct mpath_node { struct hlist_node list; struct rcu_head rcu; /* This indirection allows two different tables to point to the same * mesh_path structure, useful when resizing */ struct mesh_path *mpath; }; |
349eb8cf4 mac80211: annotat... |
41 42 |
static struct mesh_table __rcu *mesh_paths; static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */ |
eb2b9311f mac80211: mesh pa... |
43 |
|
f5ea9120b nl80211: add gene... |
44 |
int mesh_paths_generation; |
a2db2ed3f mac80211: impleme... |
45 |
int mpp_paths_generation; |
6b86bd62a mac80211: mesh: m... |
46 47 |
/* This lock will have the grow table function as writer and add / delete nodes |
239289e44 mac80211: Consoli... |
48 49 50 51 |
* as readers. RCU provides sufficient protection only when reading the table * (i.e. doing lookups). Adding or adding or removing nodes requires we take * the read lock or we risk operating on an old table. The write lock is only * needed when modifying the number of buckets a table. |
6b86bd62a mac80211: mesh: m... |
52 53 |
*/ static DEFINE_RWLOCK(pathtbl_resize_lock); |
349eb8cf4 mac80211: annotat... |
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
static inline struct mesh_table *resize_dereference_mesh_paths(void) { return rcu_dereference_protected(mesh_paths, lockdep_is_held(&pathtbl_resize_lock)); } static inline struct mesh_table *resize_dereference_mpp_paths(void) { return rcu_dereference_protected(mpp_paths, lockdep_is_held(&pathtbl_resize_lock)); } /* * CAREFUL -- "tbl" must not be an expression, * in particular not an rcu_dereference(), since * it's used twice. So it is illegal to do * for_each_mesh_entry(rcu_dereference(...), ...) */ |
b67bfe0d4 hlist: drop the n... |
72 |
#define for_each_mesh_entry(tbl, node, i) \ |
349eb8cf4 mac80211: annotat... |
73 |
for (i = 0; i <= tbl->hash_mask; i++) \ |
b67bfe0d4 hlist: drop the n... |
74 |
hlist_for_each_entry_rcu(node, &tbl->hash_buckets[i], list) |
349eb8cf4 mac80211: annotat... |
75 |
|
6b86bd62a mac80211: mesh: m... |
76 77 78 79 |
static struct mesh_table *mesh_table_alloc(int size_order) { int i; struct mesh_table *newtbl; |
d676ff493 mac80211: Don't s... |
80 |
newtbl = kmalloc(sizeof(struct mesh_table), GFP_ATOMIC); |
6b86bd62a mac80211: mesh: m... |
81 82 83 84 |
if (!newtbl) return NULL; newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * |
d676ff493 mac80211: Don't s... |
85 |
(1 << size_order), GFP_ATOMIC); |
6b86bd62a mac80211: mesh: m... |
86 87 88 89 90 91 92 |
if (!newtbl->hash_buckets) { kfree(newtbl); return NULL; } newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * |
d676ff493 mac80211: Don't s... |
93 |
(1 << size_order), GFP_ATOMIC); |
6b86bd62a mac80211: mesh: m... |
94 95 96 97 98 99 100 101 102 103 104 105 106 |
if (!newtbl->hashwlock) { kfree(newtbl->hash_buckets); kfree(newtbl); return NULL; } newtbl->size_order = size_order; newtbl->hash_mask = (1 << size_order) - 1; atomic_set(&newtbl->entries, 0); get_random_bytes(&newtbl->hash_rnd, sizeof(newtbl->hash_rnd)); for (i = 0; i <= newtbl->hash_mask; i++) spin_lock_init(&newtbl->hashwlock[i]); |
5ee68e5b3 mac80211: mesh ga... |
107 |
spin_lock_init(&newtbl->gates_lock); |
6b86bd62a mac80211: mesh: m... |
108 109 110 |
return newtbl; } |
18889231e mac80211: Move mp... |
111 112 113 114 115 116 |
static void __mesh_table_free(struct mesh_table *tbl) { kfree(tbl->hash_buckets); kfree(tbl->hashwlock); kfree(tbl); } |
6b86bd62a mac80211: mesh: m... |
117 |
static void mesh_table_free(struct mesh_table *tbl, bool free_leafs) |
18889231e mac80211: Move mp... |
118 119 120 |
{ struct hlist_head *mesh_hash; struct hlist_node *p, *q; |
5ee68e5b3 mac80211: mesh ga... |
121 |
struct mpath_node *gate; |
18889231e mac80211: Move mp... |
122 123 124 125 |
int i; mesh_hash = tbl->hash_buckets; for (i = 0; i <= tbl->hash_mask; i++) { |
9b84b8089 mac80211: Fix loc... |
126 |
spin_lock_bh(&tbl->hashwlock[i]); |
18889231e mac80211: Move mp... |
127 128 129 130 |
hlist_for_each_safe(p, q, &mesh_hash[i]) { tbl->free_node(p, free_leafs); atomic_dec(&tbl->entries); } |
9b84b8089 mac80211: Fix loc... |
131 |
spin_unlock_bh(&tbl->hashwlock[i]); |
18889231e mac80211: Move mp... |
132 |
} |
5ee68e5b3 mac80211: mesh ga... |
133 134 |
if (free_leafs) { spin_lock_bh(&tbl->gates_lock); |
b67bfe0d4 hlist: drop the n... |
135 |
hlist_for_each_entry_safe(gate, q, |
5ee68e5b3 mac80211: mesh ga... |
136 137 138 139 140 141 142 |
tbl->known_gates, list) { hlist_del(&gate->list); kfree(gate); } kfree(tbl->known_gates); spin_unlock_bh(&tbl->gates_lock); } |
18889231e mac80211: Move mp... |
143 144 |
__mesh_table_free(tbl); } |
a3e6b12c0 mac80211: Allocat... |
145 |
static int mesh_table_grow(struct mesh_table *oldtbl, |
6b86bd62a mac80211: mesh: m... |
146 |
struct mesh_table *newtbl) |
18889231e mac80211: Move mp... |
147 |
{ |
18889231e mac80211: Move mp... |
148 149 150 |
struct hlist_head *oldhash; struct hlist_node *p, *q; int i; |
a3e6b12c0 mac80211: Allocat... |
151 152 153 |
if (atomic_read(&oldtbl->entries) < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1)) return -EAGAIN; |
18889231e mac80211: Move mp... |
154 |
|
a3e6b12c0 mac80211: Allocat... |
155 156 157 |
newtbl->free_node = oldtbl->free_node; newtbl->mean_chain_len = oldtbl->mean_chain_len; newtbl->copy_node = oldtbl->copy_node; |
5ee68e5b3 mac80211: mesh ga... |
158 |
newtbl->known_gates = oldtbl->known_gates; |
a3e6b12c0 mac80211: Allocat... |
159 |
atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries)); |
18889231e mac80211: Move mp... |
160 |
|
a3e6b12c0 mac80211: Allocat... |
161 162 |
oldhash = oldtbl->hash_buckets; for (i = 0; i <= oldtbl->hash_mask; i++) |
18889231e mac80211: Move mp... |
163 |
hlist_for_each(p, &oldhash[i]) |
a3e6b12c0 mac80211: Allocat... |
164 |
if (oldtbl->copy_node(p, newtbl) < 0) |
18889231e mac80211: Move mp... |
165 |
goto errcopy; |
a3e6b12c0 mac80211: Allocat... |
166 |
return 0; |
18889231e mac80211: Move mp... |
167 168 169 170 |
errcopy: for (i = 0; i <= newtbl->hash_mask; i++) { hlist_for_each_safe(p, q, &newtbl->hash_buckets[i]) |
a3e6b12c0 mac80211: Allocat... |
171 |
oldtbl->free_node(p, 0); |
18889231e mac80211: Move mp... |
172 |
} |
a3e6b12c0 mac80211: Allocat... |
173 |
return -ENOMEM; |
18889231e mac80211: Move mp... |
174 |
} |
4a3cb702b mac80211: constif... |
175 |
static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata, |
6b86bd62a mac80211: mesh: m... |
176 177 178 |
struct mesh_table *tbl) { /* Use last four bytes of hw addr and interface index as hash index */ |
bf7cd94dc mac80211: clean u... |
179 180 |
return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd) & tbl->hash_mask; |
6b86bd62a mac80211: mesh: m... |
181 |
} |
f5ea9120b nl80211: add gene... |
182 |
|
eb2b9311f mac80211: mesh pa... |
183 184 185 186 187 188 189 190 191 192 193 194 |
/** * * mesh_path_assign_nexthop - update mesh path next hop * * @mpath: mesh path to update * @sta: next hop to assign * * Locking: mpath->state_lock must be held when calling this function */ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) { |
10c836d78 mac80211: Assign ... |
195 196 |
struct sk_buff *skb; struct ieee80211_hdr *hdr; |
10c836d78 mac80211: Assign ... |
197 |
unsigned long flags; |
d0709a651 mac80211: RCU-ify... |
198 |
rcu_assign_pointer(mpath->next_hop, sta); |
10c836d78 mac80211: Assign ... |
199 |
|
10c836d78 mac80211: Assign ... |
200 |
spin_lock_irqsave(&mpath->frame_queue.lock, flags); |
b22bd5221 mac80211: use skb... |
201 |
skb_queue_walk(&mpath->frame_queue, skb) { |
10c836d78 mac80211: Assign ... |
202 203 |
hdr = (struct ieee80211_hdr *) skb->data; memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN); |
7e3c88660 mac80211: failed ... |
204 |
memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN); |
3f52b7e32 mac80211: mesh po... |
205 |
ieee80211_mps_set_frame_flags(sta->sdata, sta, hdr); |
10c836d78 mac80211: Assign ... |
206 |
} |
10c836d78 mac80211: Assign ... |
207 |
spin_unlock_irqrestore(&mpath->frame_queue.lock, flags); |
eb2b9311f mac80211: mesh pa... |
208 |
} |
5ee68e5b3 mac80211: mesh ga... |
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
static void prepare_for_gate(struct sk_buff *skb, char *dst_addr, struct mesh_path *gate_mpath) { struct ieee80211_hdr *hdr; struct ieee80211s_hdr *mshdr; int mesh_hdrlen, hdrlen; char *next_hop; hdr = (struct ieee80211_hdr *) skb->data; hdrlen = ieee80211_hdrlen(hdr->frame_control); mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); if (!(mshdr->flags & MESH_FLAGS_AE)) { /* size of the fixed part of the mesh header */ mesh_hdrlen = 6; /* make room for the two extended addresses */ skb_push(skb, 2 * ETH_ALEN); memmove(skb->data, hdr, hdrlen + mesh_hdrlen); hdr = (struct ieee80211_hdr *) skb->data; /* we preserve the previous mesh header and only add * the new addreses */ mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); mshdr->flags = MESH_FLAGS_AE_A5_A6; memcpy(mshdr->eaddr1, hdr->addr3, ETH_ALEN); memcpy(mshdr->eaddr2, hdr->addr4, ETH_ALEN); } /* update next hop */ hdr = (struct ieee80211_hdr *) skb->data; rcu_read_lock(); next_hop = rcu_dereference(gate_mpath->next_hop)->sta.addr; memcpy(hdr->addr1, next_hop, ETH_ALEN); rcu_read_unlock(); |
7e3c88660 mac80211: failed ... |
245 |
memcpy(hdr->addr2, gate_mpath->sdata->vif.addr, ETH_ALEN); |
5ee68e5b3 mac80211: mesh ga... |
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
memcpy(hdr->addr3, dst_addr, ETH_ALEN); } /** * * mesh_path_move_to_queue - Move or copy frames from one mpath queue to another * * This function is used to transfer or copy frames from an unresolved mpath to * a gate mpath. The function also adds the Address Extension field and * updates the next hop. * * If a frame already has an Address Extension field, only the next hop and * destination addresses are updated. * * The gate mpath must be an active mpath with a valid mpath->next_hop. * * @mpath: An active mpath the frames will be sent to (i.e. the gate) * @from_mpath: The failed mpath * @copy: When true, copy all the frames to the new mpath queue. When false, * move them. */ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, struct mesh_path *from_mpath, bool copy) { |
4bd4c2dd8 mac80211: clean u... |
271 272 |
struct sk_buff *skb, *fskb, *tmp; struct sk_buff_head failq; |
5ee68e5b3 mac80211: mesh ga... |
273 |
unsigned long flags; |
5ee68e5b3 mac80211: mesh ga... |
274 |
|
8c5bb1fad mac80211: remove ... |
275 276 277 278 |
if (WARN_ON(gate_mpath == from_mpath)) return; if (WARN_ON(!gate_mpath->next_hop)) return; |
5ee68e5b3 mac80211: mesh ga... |
279 |
|
5ee68e5b3 mac80211: mesh ga... |
280 281 282 283 284 |
__skb_queue_head_init(&failq); spin_lock_irqsave(&from_mpath->frame_queue.lock, flags); skb_queue_splice_init(&from_mpath->frame_queue, &failq); spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags); |
4bd4c2dd8 mac80211: clean u... |
285 286 287 288 289 290 |
skb_queue_walk_safe(&failq, fskb, tmp) { if (skb_queue_len(&gate_mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN) { mpath_dbg(gate_mpath->sdata, "mpath queue full! "); break; |
817a53d98 mac80211: refacto... |
291 |
} |
5ee68e5b3 mac80211: mesh ga... |
292 |
|
4bd4c2dd8 mac80211: clean u... |
293 294 295 |
skb = skb_copy(fskb, GFP_ATOMIC); if (WARN_ON(!skb)) break; |
5ee68e5b3 mac80211: mesh ga... |
296 |
prepare_for_gate(skb, gate_mpath->dst, gate_mpath); |
4bd4c2dd8 mac80211: clean u... |
297 298 299 300 301 302 303 |
skb_queue_tail(&gate_mpath->frame_queue, skb); if (copy) continue; __skb_unlink(fskb, &failq); kfree_skb(fskb); |
5ee68e5b3 mac80211: mesh ga... |
304 |
} |
bdcbd8e0e mac80211: clean u... |
305 306 307 |
mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames ", gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue)); |
5ee68e5b3 mac80211: mesh ga... |
308 309 310 311 312 313 314 315 |
if (!copy) return; spin_lock_irqsave(&from_mpath->frame_queue.lock, flags); skb_queue_splice(&failq, &from_mpath->frame_queue); spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags); } |
eb2b9311f mac80211: mesh pa... |
316 |
|
4a3cb702b mac80211: constif... |
317 318 |
static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst, struct ieee80211_sub_if_data *sdata) |
eb2b9311f mac80211: mesh pa... |
319 320 |
{ struct mesh_path *mpath; |
eb2b9311f mac80211: mesh pa... |
321 |
struct hlist_head *bucket; |
eb2b9311f mac80211: mesh pa... |
322 |
struct mpath_node *node; |
f698d856f replace net_devic... |
323 |
bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)]; |
b67bfe0d4 hlist: drop the n... |
324 |
hlist_for_each_entry_rcu(node, bucket, list) { |
eb2b9311f mac80211: mesh pa... |
325 |
mpath = node->mpath; |
f698d856f replace net_devic... |
326 |
if (mpath->sdata == sdata && |
b203ca391 mac80211: Convert... |
327 |
ether_addr_equal(dst, mpath->dst)) { |
bf7cd94dc mac80211: clean u... |
328 |
if (mpath_expired(mpath)) { |
eb2b9311f mac80211: mesh pa... |
329 |
spin_lock_bh(&mpath->state_lock); |
ad99d1411 mac80211: Remove ... |
330 |
mpath->flags &= ~MESH_PATH_ACTIVE; |
eb2b9311f mac80211: mesh pa... |
331 332 333 334 335 336 337 |
spin_unlock_bh(&mpath->state_lock); } return mpath; } } return NULL; } |
239289e44 mac80211: Consoli... |
338 339 |
/** * mesh_path_lookup - look up a path in the mesh path table |
239289e44 mac80211: Consoli... |
340 |
* @sdata: local subif |
bf7cd94dc mac80211: clean u... |
341 |
* @dst: hardware address (ETH_ALEN length) of destination |
239289e44 mac80211: Consoli... |
342 343 344 345 346 |
* * Returns: pointer to the mesh path structure, or NULL if not found * * Locking: must be called within a read rcu section. */ |
bf7cd94dc mac80211: clean u... |
347 348 |
struct mesh_path * mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst) |
79617deee mac80211: mesh po... |
349 |
{ |
5ad20dd14 mac80211: rename ... |
350 |
return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata); |
239289e44 mac80211: Consoli... |
351 |
} |
79617deee mac80211: mesh po... |
352 |
|
bf7cd94dc mac80211: clean u... |
353 354 |
struct mesh_path * mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst) |
239289e44 mac80211: Consoli... |
355 |
{ |
5ad20dd14 mac80211: rename ... |
356 |
return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata); |
79617deee mac80211: mesh po... |
357 |
} |
eb2b9311f mac80211: mesh pa... |
358 359 360 |
/** * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index * @idx: index |
f698d856f replace net_devic... |
361 |
* @sdata: local subif, or NULL for all entries |
eb2b9311f mac80211: mesh pa... |
362 363 364 365 366 |
* * Returns: pointer to the mesh path structure, or NULL if not found. * * Locking: must be called within a read rcu section. */ |
bf7cd94dc mac80211: clean u... |
367 368 |
struct mesh_path * mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx) |
eb2b9311f mac80211: mesh pa... |
369 |
{ |
349eb8cf4 mac80211: annotat... |
370 |
struct mesh_table *tbl = rcu_dereference(mesh_paths); |
eb2b9311f mac80211: mesh pa... |
371 |
struct mpath_node *node; |
eb2b9311f mac80211: mesh pa... |
372 373 |
int i; int j = 0; |
b67bfe0d4 hlist: drop the n... |
374 |
for_each_mesh_entry(tbl, node, i) { |
f698d856f replace net_devic... |
375 |
if (sdata && node->mpath->sdata != sdata) |
2a8ca29a8 mac80211: fix mes... |
376 |
continue; |
eb2b9311f mac80211: mesh pa... |
377 |
if (j++ == idx) { |
bf7cd94dc mac80211: clean u... |
378 |
if (mpath_expired(node->mpath)) { |
eb2b9311f mac80211: mesh pa... |
379 |
spin_lock_bh(&node->mpath->state_lock); |
ad99d1411 mac80211: Remove ... |
380 |
node->mpath->flags &= ~MESH_PATH_ACTIVE; |
eb2b9311f mac80211: mesh pa... |
381 382 383 384 |
spin_unlock_bh(&node->mpath->state_lock); } return node->mpath; } |
2a8ca29a8 mac80211: fix mes... |
385 |
} |
eb2b9311f mac80211: mesh pa... |
386 387 388 |
return NULL; } |
5ee68e5b3 mac80211: mesh ga... |
389 |
/** |
a2db2ed3f mac80211: impleme... |
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
* mpp_path_lookup_by_idx - look up a path in the proxy path table by its index * @idx: index * @sdata: local subif, or NULL for all entries * * Returns: pointer to the proxy path structure, or NULL if not found. * * Locking: must be called within a read rcu section. */ struct mesh_path * mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx) { struct mesh_table *tbl = rcu_dereference(mpp_paths); struct mpath_node *node; int i; int j = 0; for_each_mesh_entry(tbl, node, i) { if (sdata && node->mpath->sdata != sdata) continue; if (j++ == idx) return node->mpath; } return NULL; } /** |
30be52e44 mac80211: fix RCU... |
417 418 |
* mesh_path_add_gate - add the given mpath to a mesh gate to our path table * @mpath: gate path to add to table |
5ee68e5b3 mac80211: mesh ga... |
419 |
*/ |
30be52e44 mac80211: fix RCU... |
420 |
int mesh_path_add_gate(struct mesh_path *mpath) |
5ee68e5b3 mac80211: mesh ga... |
421 |
{ |
30be52e44 mac80211: fix RCU... |
422 |
struct mesh_table *tbl; |
5ee68e5b3 mac80211: mesh ga... |
423 |
struct mpath_node *gate, *new_gate; |
5ee68e5b3 mac80211: mesh ga... |
424 425 426 |
int err; rcu_read_lock(); |
30be52e44 mac80211: fix RCU... |
427 |
tbl = rcu_dereference(mesh_paths); |
5ee68e5b3 mac80211: mesh ga... |
428 |
|
b67bfe0d4 hlist: drop the n... |
429 |
hlist_for_each_entry_rcu(gate, tbl->known_gates, list) |
5ee68e5b3 mac80211: mesh ga... |
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
if (gate->mpath == mpath) { err = -EEXIST; goto err_rcu; } new_gate = kzalloc(sizeof(struct mpath_node), GFP_ATOMIC); if (!new_gate) { err = -ENOMEM; goto err_rcu; } mpath->is_gate = true; mpath->sdata->u.mesh.num_gates++; new_gate->mpath = mpath; spin_lock_bh(&tbl->gates_lock); hlist_add_head_rcu(&new_gate->list, tbl->known_gates); spin_unlock_bh(&tbl->gates_lock); |
bdcbd8e0e mac80211: clean u... |
447 448 449 450 |
mpath_dbg(mpath->sdata, "Mesh path: Recorded new gate: %pM. %d known gates ", mpath->dst, mpath->sdata->u.mesh.num_gates); |
bf7cd94dc mac80211: clean u... |
451 |
err = 0; |
5ee68e5b3 mac80211: mesh ga... |
452 453 454 455 456 457 458 459 460 461 |
err_rcu: rcu_read_unlock(); return err; } /** * mesh_gate_del - remove a mesh gate from the list of known gates * @tbl: table which holds our list of known gates * @mpath: gate mpath * |
5ee68e5b3 mac80211: mesh ga... |
462 463 |
* Locking: must be called inside rcu_read_lock() section */ |
bf7cd94dc mac80211: clean u... |
464 |
static void mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) |
5ee68e5b3 mac80211: mesh ga... |
465 466 |
{ struct mpath_node *gate; |
b67bfe0d4 hlist: drop the n... |
467 |
struct hlist_node *q; |
5ee68e5b3 mac80211: mesh ga... |
468 |
|
b67bfe0d4 hlist: drop the n... |
469 |
hlist_for_each_entry_safe(gate, q, tbl->known_gates, list) { |
bf7cd94dc mac80211: clean u... |
470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
if (gate->mpath != mpath) continue; spin_lock_bh(&tbl->gates_lock); hlist_del_rcu(&gate->list); kfree_rcu(gate, rcu); spin_unlock_bh(&tbl->gates_lock); mpath->sdata->u.mesh.num_gates--; mpath->is_gate = false; mpath_dbg(mpath->sdata, "Mesh path: Deleted gate: %pM. %d known gates ", mpath->dst, mpath->sdata->u.mesh.num_gates); break; } |
5ee68e5b3 mac80211: mesh ga... |
484 485 486 |
} /** |
5ee68e5b3 mac80211: mesh ga... |
487 488 489 490 491 492 493 |
* mesh_gate_num - number of gates known to this interface * @sdata: subif data */ int mesh_gate_num(struct ieee80211_sub_if_data *sdata) { return sdata->u.mesh.num_gates; } |
eb2b9311f mac80211: mesh pa... |
494 495 |
/** * mesh_path_add - allocate and add a new path to the mesh path table |
bf7cd94dc mac80211: clean u... |
496 |
* @dst: destination address of the path (ETH_ALEN length) |
f698d856f replace net_devic... |
497 |
* @sdata: local subif |
eb2b9311f mac80211: mesh pa... |
498 |
* |
af901ca18 tree-wide: fix as... |
499 |
* Returns: 0 on success |
eb2b9311f mac80211: mesh pa... |
500 501 502 |
* * State: the initial state of the new path is set to 0 */ |
ae76eef02 mac80211: return ... |
503 504 |
struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst) |
eb2b9311f mac80211: mesh pa... |
505 |
{ |
18889231e mac80211: Move mp... |
506 507 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; |
349eb8cf4 mac80211: annotat... |
508 |
struct mesh_table *tbl; |
eb2b9311f mac80211: mesh pa... |
509 510 511 |
struct mesh_path *mpath, *new_mpath; struct mpath_node *node, *new_node; struct hlist_head *bucket; |
eb2b9311f mac80211: mesh pa... |
512 |
int grow = 0; |
ae76eef02 mac80211: return ... |
513 |
int err; |
eb2b9311f mac80211: mesh pa... |
514 |
u32 hash_idx; |
b203ca391 mac80211: Convert... |
515 |
if (ether_addr_equal(dst, sdata->vif.addr)) |
eb2b9311f mac80211: mesh pa... |
516 |
/* never add ourselves as neighbours */ |
ae76eef02 mac80211: return ... |
517 |
return ERR_PTR(-ENOTSUPP); |
eb2b9311f mac80211: mesh pa... |
518 519 |
if (is_multicast_ether_addr(dst)) |
ae76eef02 mac80211: return ... |
520 |
return ERR_PTR(-ENOTSUPP); |
eb2b9311f mac80211: mesh pa... |
521 |
|
472dbc45d mac80211: split o... |
522 |
if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0) |
ae76eef02 mac80211: return ... |
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
return ERR_PTR(-ENOSPC); read_lock_bh(&pathtbl_resize_lock); tbl = resize_dereference_mesh_paths(); hash_idx = mesh_table_hash(dst, sdata, tbl); bucket = &tbl->hash_buckets[hash_idx]; spin_lock(&tbl->hashwlock[hash_idx]); hlist_for_each_entry(node, bucket, list) { mpath = node->mpath; if (mpath->sdata == sdata && ether_addr_equal(dst, mpath->dst)) goto found; } |
eb2b9311f mac80211: mesh pa... |
539 |
|
402d7752e mac80211: Brush u... |
540 |
err = -ENOMEM; |
18889231e mac80211: Move mp... |
541 |
new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); |
402d7752e mac80211: Brush u... |
542 543 |
if (!new_mpath) goto err_path_alloc; |
18889231e mac80211: Move mp... |
544 |
new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); |
402d7752e mac80211: Brush u... |
545 546 |
if (!new_node) goto err_node_alloc; |
f84e71a94 Fix GFP_KERNEL al... |
547 |
|
eb2b9311f mac80211: mesh pa... |
548 |
memcpy(new_mpath->dst, dst, ETH_ALEN); |
e83e6541c mac80211: use eth... |
549 |
eth_broadcast_addr(new_mpath->rann_snd_addr); |
35bcd5911 mac80211: fix the... |
550 |
new_mpath->is_root = false; |
f698d856f replace net_devic... |
551 |
new_mpath->sdata = sdata; |
eb2b9311f mac80211: mesh pa... |
552 553 |
new_mpath->flags = 0; skb_queue_head_init(&new_mpath->frame_queue); |
eb2b9311f mac80211: mesh pa... |
554 555 556 557 558 559 |
new_node->mpath = new_mpath; new_mpath->timer.data = (unsigned long) new_mpath; new_mpath->timer.function = mesh_path_timer; new_mpath->exp_time = jiffies; spin_lock_init(&new_mpath->state_lock); init_timer(&new_mpath->timer); |
eb2b9311f mac80211: mesh pa... |
560 |
hlist_add_head_rcu(&new_node->list, bucket); |
349eb8cf4 mac80211: annotat... |
561 562 |
if (atomic_inc_return(&tbl->entries) >= tbl->mean_chain_len * (tbl->hash_mask + 1)) |
eb2b9311f mac80211: mesh pa... |
563 |
grow = 1; |
f5ea9120b nl80211: add gene... |
564 |
mesh_paths_generation++; |
402d7752e mac80211: Brush u... |
565 |
if (grow) { |
18889231e mac80211: Move mp... |
566 |
set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); |
64592c8fc mac80211: use com... |
567 |
ieee80211_queue_work(&local->hw, &sdata->work); |
eb2b9311f mac80211: mesh pa... |
568 |
} |
ae76eef02 mac80211: return ... |
569 570 |
mpath = new_mpath; found: |
f06c7885c mac80211: fix sma... |
571 |
spin_unlock(&tbl->hashwlock[hash_idx]); |
9b84b8089 mac80211: Fix loc... |
572 |
read_unlock_bh(&pathtbl_resize_lock); |
ae76eef02 mac80211: return ... |
573 |
return mpath; |
402d7752e mac80211: Brush u... |
574 575 576 |
err_node_alloc: kfree(new_mpath); err_path_alloc: |
472dbc45d mac80211: split o... |
577 |
atomic_dec(&sdata->u.mesh.mpaths); |
ae76eef02 mac80211: return ... |
578 579 580 |
spin_unlock(&tbl->hashwlock[hash_idx]); read_unlock_bh(&pathtbl_resize_lock); return ERR_PTR(err); |
eb2b9311f mac80211: mesh pa... |
581 |
} |
1928ecab6 mac80211: fix and... |
582 583 584 585 586 587 |
static void mesh_table_free_rcu(struct rcu_head *rcu) { struct mesh_table *tbl = container_of(rcu, struct mesh_table, rcu_head); mesh_table_free(tbl, false); } |
18889231e mac80211: Move mp... |
588 589 590 |
void mesh_mpath_table_grow(void) { struct mesh_table *oldtbl, *newtbl; |
9b84b8089 mac80211: Fix loc... |
591 |
write_lock_bh(&pathtbl_resize_lock); |
349eb8cf4 mac80211: annotat... |
592 593 |
oldtbl = resize_dereference_mesh_paths(); newtbl = mesh_table_alloc(oldtbl->size_order + 1); |
1928ecab6 mac80211: fix and... |
594 595 |
if (!newtbl) goto out; |
349eb8cf4 mac80211: annotat... |
596 |
if (mesh_table_grow(oldtbl, newtbl) < 0) { |
a3e6b12c0 mac80211: Allocat... |
597 |
__mesh_table_free(newtbl); |
1928ecab6 mac80211: fix and... |
598 |
goto out; |
18889231e mac80211: Move mp... |
599 600 |
} rcu_assign_pointer(mesh_paths, newtbl); |
18889231e mac80211: Move mp... |
601 |
|
1928ecab6 mac80211: fix and... |
602 603 604 605 |
call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu); out: write_unlock_bh(&pathtbl_resize_lock); |
18889231e mac80211: Move mp... |
606 607 608 609 610 |
} void mesh_mpp_table_grow(void) { struct mesh_table *oldtbl, *newtbl; |
9b84b8089 mac80211: Fix loc... |
611 |
write_lock_bh(&pathtbl_resize_lock); |
349eb8cf4 mac80211: annotat... |
612 613 |
oldtbl = resize_dereference_mpp_paths(); newtbl = mesh_table_alloc(oldtbl->size_order + 1); |
1928ecab6 mac80211: fix and... |
614 615 |
if (!newtbl) goto out; |
349eb8cf4 mac80211: annotat... |
616 |
if (mesh_table_grow(oldtbl, newtbl) < 0) { |
a3e6b12c0 mac80211: Allocat... |
617 |
__mesh_table_free(newtbl); |
1928ecab6 mac80211: fix and... |
618 |
goto out; |
18889231e mac80211: Move mp... |
619 620 |
} rcu_assign_pointer(mpp_paths, newtbl); |
1928ecab6 mac80211: fix and... |
621 |
call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu); |
18889231e mac80211: Move mp... |
622 |
|
1928ecab6 mac80211: fix and... |
623 624 |
out: write_unlock_bh(&pathtbl_resize_lock); |
18889231e mac80211: Move mp... |
625 |
} |
eb2b9311f mac80211: mesh pa... |
626 |
|
bf7cd94dc mac80211: clean u... |
627 628 |
int mpp_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst, const u8 *mpp) |
79617deee mac80211: mesh po... |
629 |
{ |
18889231e mac80211: Move mp... |
630 631 |
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; |
349eb8cf4 mac80211: annotat... |
632 |
struct mesh_table *tbl; |
79617deee mac80211: mesh po... |
633 634 635 |
struct mesh_path *mpath, *new_mpath; struct mpath_node *node, *new_node; struct hlist_head *bucket; |
79617deee mac80211: mesh po... |
636 637 638 |
int grow = 0; int err = 0; u32 hash_idx; |
b203ca391 mac80211: Convert... |
639 |
if (ether_addr_equal(dst, sdata->vif.addr)) |
79617deee mac80211: mesh po... |
640 641 642 643 644 645 646 |
/* never add ourselves as neighbours */ return -ENOTSUPP; if (is_multicast_ether_addr(dst)) return -ENOTSUPP; err = -ENOMEM; |
18889231e mac80211: Move mp... |
647 |
new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); |
79617deee mac80211: mesh po... |
648 649 |
if (!new_mpath) goto err_path_alloc; |
18889231e mac80211: Move mp... |
650 |
new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); |
79617deee mac80211: mesh po... |
651 652 |
if (!new_node) goto err_node_alloc; |
9b84b8089 mac80211: Fix loc... |
653 |
read_lock_bh(&pathtbl_resize_lock); |
79617deee mac80211: mesh po... |
654 655 656 657 658 659 |
memcpy(new_mpath->dst, dst, ETH_ALEN); memcpy(new_mpath->mpp, mpp, ETH_ALEN); new_mpath->sdata = sdata; new_mpath->flags = 0; skb_queue_head_init(&new_mpath->frame_queue); new_node->mpath = new_mpath; |
c61336611 mac80211: mesh ga... |
660 |
init_timer(&new_mpath->timer); |
79617deee mac80211: mesh po... |
661 662 |
new_mpath->exp_time = jiffies; spin_lock_init(&new_mpath->state_lock); |
349eb8cf4 mac80211: annotat... |
663 |
tbl = resize_dereference_mpp_paths(); |
79617deee mac80211: mesh po... |
664 |
|
349eb8cf4 mac80211: annotat... |
665 666 |
hash_idx = mesh_table_hash(dst, sdata, tbl); bucket = &tbl->hash_buckets[hash_idx]; |
f06c7885c mac80211: fix sma... |
667 |
spin_lock(&tbl->hashwlock[hash_idx]); |
79617deee mac80211: mesh po... |
668 669 |
err = -EEXIST; |
b67bfe0d4 hlist: drop the n... |
670 |
hlist_for_each_entry(node, bucket, list) { |
79617deee mac80211: mesh po... |
671 |
mpath = node->mpath; |
888d04dfb mac80211: use com... |
672 |
if (mpath->sdata == sdata && |
b203ca391 mac80211: Convert... |
673 |
ether_addr_equal(dst, mpath->dst)) |
79617deee mac80211: mesh po... |
674 675 676 677 |
goto err_exists; } hlist_add_head_rcu(&new_node->list, bucket); |
349eb8cf4 mac80211: annotat... |
678 679 |
if (atomic_inc_return(&tbl->entries) >= tbl->mean_chain_len * (tbl->hash_mask + 1)) |
79617deee mac80211: mesh po... |
680 |
grow = 1; |
f06c7885c mac80211: fix sma... |
681 |
spin_unlock(&tbl->hashwlock[hash_idx]); |
9b84b8089 mac80211: Fix loc... |
682 |
read_unlock_bh(&pathtbl_resize_lock); |
a2db2ed3f mac80211: impleme... |
683 684 |
mpp_paths_generation++; |
79617deee mac80211: mesh po... |
685 |
if (grow) { |
18889231e mac80211: Move mp... |
686 |
set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
64592c8fc mac80211: use com... |
687 |
ieee80211_queue_work(&local->hw, &sdata->work); |
79617deee mac80211: mesh po... |
688 689 690 691 |
} return 0; err_exists: |
f06c7885c mac80211: fix sma... |
692 |
spin_unlock(&tbl->hashwlock[hash_idx]); |
9b84b8089 mac80211: Fix loc... |
693 |
read_unlock_bh(&pathtbl_resize_lock); |
79617deee mac80211: mesh po... |
694 695 696 697 698 699 |
kfree(new_node); err_node_alloc: kfree(new_mpath); err_path_alloc: return err; } |
eb2b9311f mac80211: mesh pa... |
700 701 702 703 704 705 706 707 708 709 |
/** * mesh_plink_broken - deactivates paths and sends perr when a link breaks * * @sta: broken peer link * * This function must be called from the rate control algorithm if enough * delivery errors suggest that a peer link is no longer usable. */ void mesh_plink_broken(struct sta_info *sta) { |
349eb8cf4 mac80211: annotat... |
710 |
struct mesh_table *tbl; |
15ff63653 mac80211: use fix... |
711 |
static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
eb2b9311f mac80211: mesh pa... |
712 713 |
struct mesh_path *mpath; struct mpath_node *node; |
f698d856f replace net_devic... |
714 |
struct ieee80211_sub_if_data *sdata = sta->sdata; |
eb2b9311f mac80211: mesh pa... |
715 716 717 |
int i; rcu_read_lock(); |
349eb8cf4 mac80211: annotat... |
718 |
tbl = rcu_dereference(mesh_paths); |
b67bfe0d4 hlist: drop the n... |
719 |
for_each_mesh_entry(tbl, node, i) { |
eb2b9311f mac80211: mesh pa... |
720 |
mpath = node->mpath; |
2688eba9d mac80211: Replace... |
721 |
if (rcu_access_pointer(mpath->next_hop) == sta && |
eb2b9311f mac80211: mesh pa... |
722 723 |
mpath->flags & MESH_PATH_ACTIVE && !(mpath->flags & MESH_PATH_FIXED)) { |
f5e50cd07 mac80211: Improve... |
724 |
spin_lock_bh(&mpath->state_lock); |
eb2b9311f mac80211: mesh pa... |
725 |
mpath->flags &= ~MESH_PATH_ACTIVE; |
d19b3bf63 mac80211: replace... |
726 |
++mpath->sn; |
eb2b9311f mac80211: mesh pa... |
727 |
spin_unlock_bh(&mpath->state_lock); |
bf7cd94dc mac80211: clean u... |
728 |
mesh_path_error_tx(sdata, |
f63f8421d mac80211: use put... |
729 730 731 |
sdata->u.mesh.mshcfg.element_ttl, mpath->dst, mpath->sn, WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast); |
f5e50cd07 mac80211: Improve... |
732 |
} |
eb2b9311f mac80211: mesh pa... |
733 734 735 |
} rcu_read_unlock(); } |
19c50b3dc mac80211: Don't i... |
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 |
static void mesh_path_node_reclaim(struct rcu_head *rp) { struct mpath_node *node = container_of(rp, struct mpath_node, rcu); struct ieee80211_sub_if_data *sdata = node->mpath->sdata; del_timer_sync(&node->mpath->timer); atomic_dec(&sdata->u.mesh.mpaths); kfree(node->mpath); kfree(node); } /* needs to be called with the corresponding hashwlock taken */ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) { struct mesh_path *mpath; mpath = node->mpath; spin_lock(&mpath->state_lock); mpath->flags |= MESH_PATH_RESOLVING; if (mpath->is_gate) mesh_gate_del(tbl, mpath); hlist_del_rcu(&node->list); call_rcu(&node->rcu, mesh_path_node_reclaim); spin_unlock(&mpath->state_lock); atomic_dec(&tbl->entries); } |
eb2b9311f mac80211: mesh pa... |
761 762 763 |
/** * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches * |
2c53040f0 net: Fix (nearly-... |
764 |
* @sta: mesh peer to match |
eb2b9311f mac80211: mesh pa... |
765 |
* |
b4e08ea14 mac80211: add PLI... |
766 767 768 |
* RCU notes: this function is called when a mesh plink transitions from * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that * allows path creation. This will happen before the sta can be freed (because |
d0709a651 mac80211: RCU-ify... |
769 770 |
* sta_info_destroy() calls this) so any reader in a rcu read block will be * protected against the plink disappearing. |
eb2b9311f mac80211: mesh pa... |
771 772 773 |
*/ void mesh_path_flush_by_nexthop(struct sta_info *sta) { |
349eb8cf4 mac80211: annotat... |
774 |
struct mesh_table *tbl; |
eb2b9311f mac80211: mesh pa... |
775 776 |
struct mesh_path *mpath; struct mpath_node *node; |
eb2b9311f mac80211: mesh pa... |
777 |
int i; |
349eb8cf4 mac80211: annotat... |
778 |
rcu_read_lock(); |
239289e44 mac80211: Consoli... |
779 780 |
read_lock_bh(&pathtbl_resize_lock); tbl = resize_dereference_mesh_paths(); |
b67bfe0d4 hlist: drop the n... |
781 |
for_each_mesh_entry(tbl, node, i) { |
eb2b9311f mac80211: mesh pa... |
782 |
mpath = node->mpath; |
2688eba9d mac80211: Replace... |
783 |
if (rcu_access_pointer(mpath->next_hop) == sta) { |
f06c7885c mac80211: fix sma... |
784 |
spin_lock(&tbl->hashwlock[i]); |
19c50b3dc mac80211: Don't i... |
785 |
__mesh_path_del(tbl, node); |
f06c7885c mac80211: fix sma... |
786 |
spin_unlock(&tbl->hashwlock[i]); |
19c50b3dc mac80211: Don't i... |
787 |
} |
eb2b9311f mac80211: mesh pa... |
788 |
} |
239289e44 mac80211: Consoli... |
789 |
read_unlock_bh(&pathtbl_resize_lock); |
349eb8cf4 mac80211: annotat... |
790 |
rcu_read_unlock(); |
eb2b9311f mac80211: mesh pa... |
791 |
} |
cd72e8174 mac80211: Consoli... |
792 793 |
static void table_flush_by_iface(struct mesh_table *tbl, struct ieee80211_sub_if_data *sdata) |
eb2b9311f mac80211: mesh pa... |
794 795 796 |
{ struct mesh_path *mpath; struct mpath_node *node; |
eb2b9311f mac80211: mesh pa... |
797 |
int i; |
cd72e8174 mac80211: Consoli... |
798 |
WARN_ON(!rcu_read_lock_held()); |
b67bfe0d4 hlist: drop the n... |
799 |
for_each_mesh_entry(tbl, node, i) { |
eb2b9311f mac80211: mesh pa... |
800 |
mpath = node->mpath; |
cd72e8174 mac80211: Consoli... |
801 802 |
if (mpath->sdata != sdata) continue; |
ece1a2e7e mac80211: Remove ... |
803 |
spin_lock_bh(&tbl->hashwlock[i]); |
19c50b3dc mac80211: Don't i... |
804 |
__mesh_path_del(tbl, node); |
ece1a2e7e mac80211: Remove ... |
805 |
spin_unlock_bh(&tbl->hashwlock[i]); |
eb2b9311f mac80211: mesh pa... |
806 807 |
} } |
ece1a2e7e mac80211: Remove ... |
808 809 810 811 812 |
/** * mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface * * This function deletes both mesh paths as well as mesh portal paths. * |
2c53040f0 net: Fix (nearly-... |
813 |
* @sdata: interface data to match |
ece1a2e7e mac80211: Remove ... |
814 815 816 |
* */ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) |
eb2b9311f mac80211: mesh pa... |
817 |
{ |
cd72e8174 mac80211: Consoli... |
818 |
struct mesh_table *tbl; |
d0709a651 mac80211: RCU-ify... |
819 |
|
cd72e8174 mac80211: Consoli... |
820 |
rcu_read_lock(); |
239289e44 mac80211: Consoli... |
821 822 |
read_lock_bh(&pathtbl_resize_lock); tbl = resize_dereference_mesh_paths(); |
cd72e8174 mac80211: Consoli... |
823 |
table_flush_by_iface(tbl, sdata); |
239289e44 mac80211: Consoli... |
824 |
tbl = resize_dereference_mpp_paths(); |
cd72e8174 mac80211: Consoli... |
825 |
table_flush_by_iface(tbl, sdata); |
239289e44 mac80211: Consoli... |
826 |
read_unlock_bh(&pathtbl_resize_lock); |
cd72e8174 mac80211: Consoli... |
827 |
rcu_read_unlock(); |
eb2b9311f mac80211: mesh pa... |
828 829 830 831 832 833 |
} /** * mesh_path_del - delete a mesh path from the table * * @addr: dst address (ETH_ALEN length) |
f698d856f replace net_devic... |
834 |
* @sdata: local subif |
eb2b9311f mac80211: mesh pa... |
835 |
* |
af901ca18 tree-wide: fix as... |
836 |
* Returns: 0 if successful |
eb2b9311f mac80211: mesh pa... |
837 |
*/ |
bf7cd94dc mac80211: clean u... |
838 |
int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) |
eb2b9311f mac80211: mesh pa... |
839 |
{ |
349eb8cf4 mac80211: annotat... |
840 |
struct mesh_table *tbl; |
eb2b9311f mac80211: mesh pa... |
841 842 843 |
struct mesh_path *mpath; struct mpath_node *node; struct hlist_head *bucket; |
eb2b9311f mac80211: mesh pa... |
844 845 |
int hash_idx; int err = 0; |
9b84b8089 mac80211: Fix loc... |
846 |
read_lock_bh(&pathtbl_resize_lock); |
349eb8cf4 mac80211: annotat... |
847 848 849 |
tbl = resize_dereference_mesh_paths(); hash_idx = mesh_table_hash(addr, sdata, tbl); bucket = &tbl->hash_buckets[hash_idx]; |
eb2b9311f mac80211: mesh pa... |
850 |
|
f06c7885c mac80211: fix sma... |
851 |
spin_lock(&tbl->hashwlock[hash_idx]); |
b67bfe0d4 hlist: drop the n... |
852 |
hlist_for_each_entry(node, bucket, list) { |
eb2b9311f mac80211: mesh pa... |
853 |
mpath = node->mpath; |
f698d856f replace net_devic... |
854 |
if (mpath->sdata == sdata && |
b203ca391 mac80211: Convert... |
855 |
ether_addr_equal(addr, mpath->dst)) { |
19c50b3dc mac80211: Don't i... |
856 |
__mesh_path_del(tbl, node); |
eb2b9311f mac80211: mesh pa... |
857 858 859 860 861 862 |
goto enddel; } } err = -ENXIO; enddel: |
f5ea9120b nl80211: add gene... |
863 |
mesh_paths_generation++; |
f06c7885c mac80211: fix sma... |
864 |
spin_unlock(&tbl->hashwlock[hash_idx]); |
9b84b8089 mac80211: Fix loc... |
865 |
read_unlock_bh(&pathtbl_resize_lock); |
eb2b9311f mac80211: mesh pa... |
866 867 868 869 870 871 872 873 874 875 876 877 878 |
return err; } /** * mesh_path_tx_pending - sends pending frames in a mesh path queue * * @mpath: mesh path to activate * * Locking: the state_lock of the mpath structure must NOT be held when calling * this function. */ void mesh_path_tx_pending(struct mesh_path *mpath) { |
249b405cf mac80211: Fix reg... |
879 880 881 |
if (mpath->flags & MESH_PATH_ACTIVE) ieee80211_add_pending_skbs(mpath->sdata->local, &mpath->frame_queue); |
eb2b9311f mac80211: mesh pa... |
882 883 884 |
} /** |
5ee68e5b3 mac80211: mesh ga... |
885 886 887 888 889 890 891 892 893 894 895 896 |
* mesh_path_send_to_gates - sends pending frames to all known mesh gates * * @mpath: mesh path whose queue will be emptied * * If there is only one gate, the frames are transferred from the failed mpath * queue to that gate's queue. If there are more than one gates, the frames * are copied from each gate to the next. After frames are copied, the * mpath queues are emptied onto the transmission queue. */ int mesh_path_send_to_gates(struct mesh_path *mpath) { struct ieee80211_sub_if_data *sdata = mpath->sdata; |
5ee68e5b3 mac80211: mesh ga... |
897 898 899 900 901 902 903 904 905 906 907 908 909 |
struct mesh_table *tbl; struct mesh_path *from_mpath = mpath; struct mpath_node *gate = NULL; bool copy = false; struct hlist_head *known_gates; rcu_read_lock(); tbl = rcu_dereference(mesh_paths); known_gates = tbl->known_gates; rcu_read_unlock(); if (!known_gates) return -EHOSTUNREACH; |
b67bfe0d4 hlist: drop the n... |
910 |
hlist_for_each_entry_rcu(gate, known_gates, list) { |
5ee68e5b3 mac80211: mesh ga... |
911 912 913 914 |
if (gate->mpath->sdata != sdata) continue; if (gate->mpath->flags & MESH_PATH_ACTIVE) { |
bdcbd8e0e mac80211: clean u... |
915 916 |
mpath_dbg(sdata, "Forwarding to %pM ", gate->mpath->dst); |
5ee68e5b3 mac80211: mesh ga... |
917 918 919 920 |
mesh_path_move_to_queue(gate->mpath, from_mpath, copy); from_mpath = gate->mpath; copy = true; } else { |
bdcbd8e0e mac80211: clean u... |
921 922 923 924 |
mpath_dbg(sdata, "Not forwarding %p (flags %#x) ", gate->mpath, gate->mpath->flags); |
5ee68e5b3 mac80211: mesh ga... |
925 926 |
} } |
b67bfe0d4 hlist: drop the n... |
927 |
hlist_for_each_entry_rcu(gate, known_gates, list) |
5ee68e5b3 mac80211: mesh ga... |
928 |
if (gate->mpath->sdata == sdata) { |
bdcbd8e0e mac80211: clean u... |
929 930 |
mpath_dbg(sdata, "Sending to %pM ", gate->mpath->dst); |
5ee68e5b3 mac80211: mesh ga... |
931 932 933 934 935 936 937 |
mesh_path_tx_pending(gate->mpath); } return (from_mpath == mpath) ? -EHOSTUNREACH : 0; } /** |
eb2b9311f mac80211: mesh pa... |
938 939 940 |
* mesh_path_discard_frame - discard a frame whose path could not be resolved * * @skb: frame to discard |
f698d856f replace net_devic... |
941 |
* @sdata: network subif the frame was to be sent through |
eb2b9311f mac80211: mesh pa... |
942 |
* |
eb2b9311f mac80211: mesh pa... |
943 944 |
* Locking: the function must me called within a rcu_read_lock region */ |
bf7cd94dc mac80211: clean u... |
945 946 |
void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
eb2b9311f mac80211: mesh pa... |
947 |
{ |
eb2b9311f mac80211: mesh pa... |
948 |
kfree_skb(skb); |
472dbc45d mac80211: split o... |
949 |
sdata->u.mesh.mshstats.dropped_frames_no_route++; |
eb2b9311f mac80211: mesh pa... |
950 951 952 953 954 955 956 |
} /** * mesh_path_flush_pending - free the pending queue of a mesh path * * @mpath: mesh path whose queue has to be freed * |
25985edce Fix common misspe... |
957 |
* Locking: the function must me called within a rcu_read_lock region |
eb2b9311f mac80211: mesh pa... |
958 959 960 |
*/ void mesh_path_flush_pending(struct mesh_path *mpath) { |
eb2b9311f mac80211: mesh pa... |
961 |
struct sk_buff *skb; |
00e3f25c8 mac80211: fix mes... |
962 |
while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL) |
bf7cd94dc mac80211: clean u... |
963 |
mesh_path_discard_frame(mpath->sdata, skb); |
eb2b9311f mac80211: mesh pa... |
964 965 966 967 968 969 970 971 972 973 974 975 976 977 |
} /** * mesh_path_fix_nexthop - force a specific next hop for a mesh path * * @mpath: the mesh path to modify * @next_hop: the next hop to force * * Locking: this function must be called holding mpath->state_lock */ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop) { spin_lock_bh(&mpath->state_lock); mesh_path_assign_nexthop(mpath, next_hop); |
d19b3bf63 mac80211: replace... |
978 |
mpath->sn = 0xffff; |
eb2b9311f mac80211: mesh pa... |
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 |
mpath->metric = 0; mpath->hop_count = 0; mpath->exp_time = 0; mpath->flags |= MESH_PATH_FIXED; mesh_path_activate(mpath); spin_unlock_bh(&mpath->state_lock); mesh_path_tx_pending(mpath); } static void mesh_path_node_free(struct hlist_node *p, bool free_leafs) { struct mesh_path *mpath; struct mpath_node *node = hlist_entry(p, struct mpath_node, list); mpath = node->mpath; hlist_del_rcu(p); |
d0df9eecf mac80211: Deactiv... |
994 995 |
if (free_leafs) { del_timer_sync(&mpath->timer); |
eb2b9311f mac80211: mesh pa... |
996 |
kfree(mpath); |
d0df9eecf mac80211: Deactiv... |
997 |
} |
eb2b9311f mac80211: mesh pa... |
998 999 |
kfree(node); } |
4caf86c69 mac80211: Prepare... |
1000 |
static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) |
eb2b9311f mac80211: mesh pa... |
1001 1002 1003 1004 |
{ struct mesh_path *mpath; struct mpath_node *node, *new_node; u32 hash_idx; |
8566dc3fc mac80211: Fix sle... |
1005 |
new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC); |
00242c40a mac80211: Report ... |
1006 1007 |
if (new_node == NULL) return -ENOMEM; |
eb2b9311f mac80211: mesh pa... |
1008 1009 |
node = hlist_entry(p, struct mpath_node, list); mpath = node->mpath; |
eb2b9311f mac80211: mesh pa... |
1010 |
new_node->mpath = mpath; |
f698d856f replace net_devic... |
1011 |
hash_idx = mesh_table_hash(mpath->dst, mpath->sdata, newtbl); |
eb2b9311f mac80211: mesh pa... |
1012 1013 |
hlist_add_head(&new_node->list, &newtbl->hash_buckets[hash_idx]); |
4caf86c69 mac80211: Prepare... |
1014 |
return 0; |
eb2b9311f mac80211: mesh pa... |
1015 1016 1017 1018 |
} int mesh_pathtbl_init(void) { |
349eb8cf4 mac80211: annotat... |
1019 |
struct mesh_table *tbl_path, *tbl_mpp; |
4c5ade414 mac80211: handle ... |
1020 |
int ret; |
349eb8cf4 mac80211: annotat... |
1021 1022 1023 |
tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); if (!tbl_path) |
79617deee mac80211: mesh po... |
1024 |
return -ENOMEM; |
349eb8cf4 mac80211: annotat... |
1025 1026 1027 |
tbl_path->free_node = &mesh_path_node_free; tbl_path->copy_node = &mesh_path_node_copy; tbl_path->mean_chain_len = MEAN_CHAIN_LEN; |
5ee68e5b3 mac80211: mesh ga... |
1028 |
tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); |
4c5ade414 mac80211: handle ... |
1029 1030 1031 1032 |
if (!tbl_path->known_gates) { ret = -ENOMEM; goto free_path; } |
5ee68e5b3 mac80211: mesh ga... |
1033 |
INIT_HLIST_HEAD(tbl_path->known_gates); |
79617deee mac80211: mesh po... |
1034 |
|
349eb8cf4 mac80211: annotat... |
1035 1036 |
tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); if (!tbl_mpp) { |
4c5ade414 mac80211: handle ... |
1037 1038 |
ret = -ENOMEM; goto free_path; |
79617deee mac80211: mesh po... |
1039 |
} |
349eb8cf4 mac80211: annotat... |
1040 1041 1042 |
tbl_mpp->free_node = &mesh_path_node_free; tbl_mpp->copy_node = &mesh_path_node_copy; tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN; |
5ee68e5b3 mac80211: mesh ga... |
1043 |
tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC); |
4c5ade414 mac80211: handle ... |
1044 1045 1046 1047 |
if (!tbl_mpp->known_gates) { ret = -ENOMEM; goto free_mpp; } |
5ee68e5b3 mac80211: mesh ga... |
1048 |
INIT_HLIST_HEAD(tbl_mpp->known_gates); |
349eb8cf4 mac80211: annotat... |
1049 1050 1051 1052 |
/* Need no locking since this is during init */ RCU_INIT_POINTER(mesh_paths, tbl_path); RCU_INIT_POINTER(mpp_paths, tbl_mpp); |
79617deee mac80211: mesh po... |
1053 |
|
eb2b9311f mac80211: mesh pa... |
1054 |
return 0; |
4c5ade414 mac80211: handle ... |
1055 1056 1057 1058 1059 1060 |
free_mpp: mesh_table_free(tbl_mpp, true); free_path: mesh_table_free(tbl_path, true); return ret; |
eb2b9311f mac80211: mesh pa... |
1061 |
} |
f698d856f replace net_devic... |
1062 |
void mesh_path_expire(struct ieee80211_sub_if_data *sdata) |
eb2b9311f mac80211: mesh pa... |
1063 |
{ |
349eb8cf4 mac80211: annotat... |
1064 |
struct mesh_table *tbl; |
eb2b9311f mac80211: mesh pa... |
1065 1066 |
struct mesh_path *mpath; struct mpath_node *node; |
eb2b9311f mac80211: mesh pa... |
1067 |
int i; |
349eb8cf4 mac80211: annotat... |
1068 1069 |
rcu_read_lock(); tbl = rcu_dereference(mesh_paths); |
b67bfe0d4 hlist: drop the n... |
1070 |
for_each_mesh_entry(tbl, node, i) { |
f698d856f replace net_devic... |
1071 |
if (node->mpath->sdata != sdata) |
eb2b9311f mac80211: mesh pa... |
1072 1073 |
continue; mpath = node->mpath; |
eb2b9311f mac80211: mesh pa... |
1074 1075 |
if ((!(mpath->flags & MESH_PATH_RESOLVING)) && (!(mpath->flags & MESH_PATH_FIXED)) && |
f5e50cd07 mac80211: Improve... |
1076 |
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) |
bf7cd94dc mac80211: clean u... |
1077 |
mesh_path_del(mpath->sdata, mpath->dst); |
eb2b9311f mac80211: mesh pa... |
1078 |
} |
349eb8cf4 mac80211: annotat... |
1079 |
rcu_read_unlock(); |
eb2b9311f mac80211: mesh pa... |
1080 1081 1082 1083 |
} void mesh_pathtbl_unregister(void) { |
349eb8cf4 mac80211: annotat... |
1084 |
/* no need for locking during exit path */ |
33d480ce6 net: cleanup some... |
1085 1086 |
mesh_table_free(rcu_dereference_protected(mesh_paths, 1), true); mesh_table_free(rcu_dereference_protected(mpp_paths, 1), true); |
eb2b9311f mac80211: mesh pa... |
1087 |
} |