Blame view

net/mac80211/mesh_pathtbl.c 29.3 KB
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1
  /*
264d9b7d8   Rui Paulo   mac80211: update ...
2
   * Copyright (c) 2008, 2009 open80211s Ltd.
eb2b9311f   Luis Carlos Cobo   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   Luis Carlos Cobo   mac80211: mesh pa...
12
  #include <linux/random.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
14
15
16
  #include <linux/spinlock.h>
  #include <linux/string.h>
  #include <net/mac80211.h>
4777be416   Javier Cardona   mac80211: Start i...
17
  #include "wme.h"
eb2b9311f   Luis Carlos Cobo   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   Johannes Berg   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   Luis Carlos Cobo   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   Johannes Berg   mac80211: annotat...
41
42
  static struct mesh_table __rcu *mesh_paths;
  static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
43

f5ea9120b   Johannes Berg   nl80211: add gene...
44
  int mesh_paths_generation;
a2db2ed3f   Henning Rogge   mac80211: impleme...
45
  int mpp_paths_generation;
6b86bd62a   Johannes Berg   mac80211: mesh: m...
46
47
  
  /* This lock will have the grow table function as writer and add / delete nodes
239289e44   Javier Cardona   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   Johannes Berg   mac80211: mesh: m...
52
53
   */
  static DEFINE_RWLOCK(pathtbl_resize_lock);
349eb8cf4   Johannes Berg   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   Sasha Levin   hlist: drop the n...
72
  #define for_each_mesh_entry(tbl, node, i) \
349eb8cf4   Johannes Berg   mac80211: annotat...
73
  	for (i = 0; i <= tbl->hash_mask; i++) \
b67bfe0d4   Sasha Levin   hlist: drop the n...
74
  		hlist_for_each_entry_rcu(node, &tbl->hash_buckets[i], list)
349eb8cf4   Johannes Berg   mac80211: annotat...
75

6b86bd62a   Johannes Berg   mac80211: mesh: m...
76
77
78
79
  static struct mesh_table *mesh_table_alloc(int size_order)
  {
  	int i;
  	struct mesh_table *newtbl;
d676ff493   Javier Cardona   mac80211: Don't s...
80
  	newtbl = kmalloc(sizeof(struct mesh_table), GFP_ATOMIC);
6b86bd62a   Johannes Berg   mac80211: mesh: m...
81
82
83
84
  	if (!newtbl)
  		return NULL;
  
  	newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
d676ff493   Javier Cardona   mac80211: Don't s...
85
  			(1 << size_order), GFP_ATOMIC);
6b86bd62a   Johannes Berg   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   Javier Cardona   mac80211: Don't s...
93
  			(1 << size_order), GFP_ATOMIC);
6b86bd62a   Johannes Berg   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   Javier Cardona   mac80211: mesh ga...
107
  	spin_lock_init(&newtbl->gates_lock);
6b86bd62a   Johannes Berg   mac80211: mesh: m...
108
109
110
  
  	return newtbl;
  }
18889231e   Javier Cardona   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   Johannes Berg   mac80211: mesh: m...
117
  static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
18889231e   Javier Cardona   mac80211: Move mp...
118
119
120
  {
  	struct hlist_head *mesh_hash;
  	struct hlist_node *p, *q;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
121
  	struct mpath_node *gate;
18889231e   Javier Cardona   mac80211: Move mp...
122
123
124
125
  	int i;
  
  	mesh_hash = tbl->hash_buckets;
  	for (i = 0; i <= tbl->hash_mask; i++) {
9b84b8089   Javier Cardona   mac80211: Fix loc...
126
  		spin_lock_bh(&tbl->hashwlock[i]);
18889231e   Javier Cardona   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   Javier Cardona   mac80211: Fix loc...
131
  		spin_unlock_bh(&tbl->hashwlock[i]);
18889231e   Javier Cardona   mac80211: Move mp...
132
  	}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
133
134
  	if (free_leafs) {
  		spin_lock_bh(&tbl->gates_lock);
b67bfe0d4   Sasha Levin   hlist: drop the n...
135
  		hlist_for_each_entry_safe(gate, q,
5ee68e5b3   Javier Cardona   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   Javier Cardona   mac80211: Move mp...
143
144
  	__mesh_table_free(tbl);
  }
a3e6b12c0   cozybit Inc   mac80211: Allocat...
145
  static int mesh_table_grow(struct mesh_table *oldtbl,
6b86bd62a   Johannes Berg   mac80211: mesh: m...
146
  			   struct mesh_table *newtbl)
18889231e   Javier Cardona   mac80211: Move mp...
147
  {
18889231e   Javier Cardona   mac80211: Move mp...
148
149
150
  	struct hlist_head *oldhash;
  	struct hlist_node *p, *q;
  	int i;
a3e6b12c0   cozybit Inc   mac80211: Allocat...
151
152
153
  	if (atomic_read(&oldtbl->entries)
  			< oldtbl->mean_chain_len * (oldtbl->hash_mask + 1))
  		return -EAGAIN;
18889231e   Javier Cardona   mac80211: Move mp...
154

a3e6b12c0   cozybit Inc   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   Javier Cardona   mac80211: mesh ga...
158
  	newtbl->known_gates = oldtbl->known_gates;
a3e6b12c0   cozybit Inc   mac80211: Allocat...
159
  	atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));
18889231e   Javier Cardona   mac80211: Move mp...
160

a3e6b12c0   cozybit Inc   mac80211: Allocat...
161
162
  	oldhash = oldtbl->hash_buckets;
  	for (i = 0; i <= oldtbl->hash_mask; i++)
18889231e   Javier Cardona   mac80211: Move mp...
163
  		hlist_for_each(p, &oldhash[i])
a3e6b12c0   cozybit Inc   mac80211: Allocat...
164
  			if (oldtbl->copy_node(p, newtbl) < 0)
18889231e   Javier Cardona   mac80211: Move mp...
165
  				goto errcopy;
a3e6b12c0   cozybit Inc   mac80211: Allocat...
166
  	return 0;
18889231e   Javier Cardona   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   cozybit Inc   mac80211: Allocat...
171
  			oldtbl->free_node(p, 0);
18889231e   Javier Cardona   mac80211: Move mp...
172
  	}
a3e6b12c0   cozybit Inc   mac80211: Allocat...
173
  	return -ENOMEM;
18889231e   Javier Cardona   mac80211: Move mp...
174
  }
4a3cb702b   Johannes Berg   mac80211: constif...
175
  static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata,
6b86bd62a   Johannes Berg   mac80211: mesh: m...
176
177
178
  			   struct mesh_table *tbl)
  {
  	/* Use last four bytes of hw addr and interface index as hash index */
bf7cd94dc   Johannes Berg   mac80211: clean u...
179
180
  	return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex,
  			    tbl->hash_rnd) & tbl->hash_mask;
6b86bd62a   Johannes Berg   mac80211: mesh: m...
181
  }
f5ea9120b   Johannes Berg   nl80211: add gene...
182

eb2b9311f   Luis Carlos Cobo   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   Javier Cardona   mac80211: Assign ...
195
196
  	struct sk_buff *skb;
  	struct ieee80211_hdr *hdr;
10c836d78   Javier Cardona   mac80211: Assign ...
197
  	unsigned long flags;
d0709a651   Johannes Berg   mac80211: RCU-ify...
198
  	rcu_assign_pointer(mpath->next_hop, sta);
10c836d78   Javier Cardona   mac80211: Assign ...
199

10c836d78   Javier Cardona   mac80211: Assign ...
200
  	spin_lock_irqsave(&mpath->frame_queue.lock, flags);
b22bd5221   Thomas Pedersen   mac80211: use skb...
201
  	skb_queue_walk(&mpath->frame_queue, skb) {
10c836d78   Javier Cardona   mac80211: Assign ...
202
203
  		hdr = (struct ieee80211_hdr *) skb->data;
  		memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
7e3c88660   Thomas Pedersen   mac80211: failed ...
204
  		memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN);
3f52b7e32   Marco Porsch   mac80211: mesh po...
205
  		ieee80211_mps_set_frame_flags(sta->sdata, sta, hdr);
10c836d78   Javier Cardona   mac80211: Assign ...
206
  	}
10c836d78   Javier Cardona   mac80211: Assign ...
207
  	spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
208
  }
5ee68e5b3   Javier Cardona   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   Thomas Pedersen   mac80211: failed ...
245
  	memcpy(hdr->addr2, gate_mpath->sdata->vif.addr, ETH_ALEN);
5ee68e5b3   Javier Cardona   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   Thomas Pedersen   mac80211: clean u...
271
272
  	struct sk_buff *skb, *fskb, *tmp;
  	struct sk_buff_head failq;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
273
  	unsigned long flags;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
274

8c5bb1fad   Johannes Berg   mac80211: remove ...
275
276
277
278
  	if (WARN_ON(gate_mpath == from_mpath))
  		return;
  	if (WARN_ON(!gate_mpath->next_hop))
  		return;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
279

5ee68e5b3   Javier Cardona   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   Thomas Pedersen   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   John W. Linville   mac80211: refacto...
291
  		}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
292

4bd4c2dd8   Thomas Pedersen   mac80211: clean u...
293
294
295
  		skb = skb_copy(fskb, GFP_ATOMIC);
  		if (WARN_ON(!skb))
  			break;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
296
  		prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
4bd4c2dd8   Thomas Pedersen   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   Javier Cardona   mac80211: mesh ga...
304
  	}
bdcbd8e0e   Johannes Berg   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   Javier Cardona   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   Luis Carlos Cobo   mac80211: mesh pa...
316

4a3cb702b   Johannes Berg   mac80211: constif...
317
318
  static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
  				      struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
319
320
  {
  	struct mesh_path *mpath;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
321
  	struct hlist_head *bucket;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
322
  	struct mpath_node *node;
f698d856f   Jasper Bryant-Greene   replace net_devic...
323
  	bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
b67bfe0d4   Sasha Levin   hlist: drop the n...
324
  	hlist_for_each_entry_rcu(node, bucket, list) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
325
  		mpath = node->mpath;
f698d856f   Jasper Bryant-Greene   replace net_devic...
326
  		if (mpath->sdata == sdata &&
b203ca391   Joe Perches   mac80211: Convert...
327
  		    ether_addr_equal(dst, mpath->dst)) {
bf7cd94dc   Johannes Berg   mac80211: clean u...
328
  			if (mpath_expired(mpath)) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
329
  				spin_lock_bh(&mpath->state_lock);
ad99d1411   Javier Cardona   mac80211: Remove ...
330
  				mpath->flags &= ~MESH_PATH_ACTIVE;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
331
332
333
334
335
336
337
  				spin_unlock_bh(&mpath->state_lock);
  			}
  			return mpath;
  		}
  	}
  	return NULL;
  }
239289e44   Javier Cardona   mac80211: Consoli...
338
339
  /**
   * mesh_path_lookup - look up a path in the mesh path table
239289e44   Javier Cardona   mac80211: Consoli...
340
   * @sdata: local subif
bf7cd94dc   Johannes Berg   mac80211: clean u...
341
   * @dst: hardware address (ETH_ALEN length) of destination
239289e44   Javier Cardona   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   Johannes Berg   mac80211: clean u...
347
348
  struct mesh_path *
  mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
79617deee   YanBo   mac80211: mesh po...
349
  {
5ad20dd14   Luis R. Rodriguez   mac80211: rename ...
350
  	return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata);
239289e44   Javier Cardona   mac80211: Consoli...
351
  }
79617deee   YanBo   mac80211: mesh po...
352

bf7cd94dc   Johannes Berg   mac80211: clean u...
353
354
  struct mesh_path *
  mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
239289e44   Javier Cardona   mac80211: Consoli...
355
  {
5ad20dd14   Luis R. Rodriguez   mac80211: rename ...
356
  	return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata);
79617deee   YanBo   mac80211: mesh po...
357
  }
eb2b9311f   Luis Carlos Cobo   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   Jasper Bryant-Greene   replace net_devic...
361
   * @sdata: local subif, or NULL for all entries
eb2b9311f   Luis Carlos Cobo   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   Johannes Berg   mac80211: clean u...
367
368
  struct mesh_path *
  mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
369
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
370
  	struct mesh_table *tbl = rcu_dereference(mesh_paths);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
371
  	struct mpath_node *node;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
372
373
  	int i;
  	int j = 0;
b67bfe0d4   Sasha Levin   hlist: drop the n...
374
  	for_each_mesh_entry(tbl, node, i) {
f698d856f   Jasper Bryant-Greene   replace net_devic...
375
  		if (sdata && node->mpath->sdata != sdata)
2a8ca29a8   Luis Carlos Cobo   mac80211: fix mes...
376
  			continue;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
377
  		if (j++ == idx) {
bf7cd94dc   Johannes Berg   mac80211: clean u...
378
  			if (mpath_expired(node->mpath)) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
379
  				spin_lock_bh(&node->mpath->state_lock);
ad99d1411   Javier Cardona   mac80211: Remove ...
380
  				node->mpath->flags &= ~MESH_PATH_ACTIVE;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
381
382
383
384
  				spin_unlock_bh(&node->mpath->state_lock);
  			}
  			return node->mpath;
  		}
2a8ca29a8   Luis Carlos Cobo   mac80211: fix mes...
385
  	}
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
386
387
388
  
  	return NULL;
  }
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
389
  /**
a2db2ed3f   Henning Rogge   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   Johannes Berg   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   Javier Cardona   mac80211: mesh ga...
419
   */
30be52e44   Johannes Berg   mac80211: fix RCU...
420
  int mesh_path_add_gate(struct mesh_path *mpath)
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
421
  {
30be52e44   Johannes Berg   mac80211: fix RCU...
422
  	struct mesh_table *tbl;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
423
  	struct mpath_node *gate, *new_gate;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
424
425
426
  	int err;
  
  	rcu_read_lock();
30be52e44   Johannes Berg   mac80211: fix RCU...
427
  	tbl = rcu_dereference(mesh_paths);
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
428

b67bfe0d4   Sasha Levin   hlist: drop the n...
429
  	hlist_for_each_entry_rcu(gate, tbl->known_gates, list)
5ee68e5b3   Javier Cardona   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   Johannes Berg   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   Johannes Berg   mac80211: clean u...
451
  	err = 0;
5ee68e5b3   Javier Cardona   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   Javier Cardona   mac80211: mesh ga...
462
463
   * Locking: must be called inside rcu_read_lock() section
   */
bf7cd94dc   Johannes Berg   mac80211: clean u...
464
  static void mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
465
466
  {
  	struct mpath_node *gate;
b67bfe0d4   Sasha Levin   hlist: drop the n...
467
  	struct hlist_node *q;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
468

b67bfe0d4   Sasha Levin   hlist: drop the n...
469
  	hlist_for_each_entry_safe(gate, q, tbl->known_gates, list) {
bf7cd94dc   Johannes Berg   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   Javier Cardona   mac80211: mesh ga...
484
485
486
  }
  
  /**
5ee68e5b3   Javier Cardona   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   Luis Carlos Cobo   mac80211: mesh pa...
494
495
  /**
   * mesh_path_add - allocate and add a new path to the mesh path table
bf7cd94dc   Johannes Berg   mac80211: clean u...
496
   * @dst: destination address of the path (ETH_ALEN length)
f698d856f   Jasper Bryant-Greene   replace net_devic...
497
   * @sdata: local subif
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
498
   *
af901ca18   André Goddard Rosa   tree-wide: fix as...
499
   * Returns: 0 on success
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
500
501
502
   *
   * State: the initial state of the new path is set to 0
   */
ae76eef02   Bob Copeland   mac80211: return ...
503
504
  struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
  				const u8 *dst)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
505
  {
18889231e   Javier Cardona   mac80211: Move mp...
506
507
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct ieee80211_local *local = sdata->local;
349eb8cf4   Johannes Berg   mac80211: annotat...
508
  	struct mesh_table *tbl;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
509
510
511
  	struct mesh_path *mpath, *new_mpath;
  	struct mpath_node *node, *new_node;
  	struct hlist_head *bucket;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
512
  	int grow = 0;
ae76eef02   Bob Copeland   mac80211: return ...
513
  	int err;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
514
  	u32 hash_idx;
b203ca391   Joe Perches   mac80211: Convert...
515
  	if (ether_addr_equal(dst, sdata->vif.addr))
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
516
  		/* never add ourselves as neighbours */
ae76eef02   Bob Copeland   mac80211: return ...
517
  		return ERR_PTR(-ENOTSUPP);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
518
519
  
  	if (is_multicast_ether_addr(dst))
ae76eef02   Bob Copeland   mac80211: return ...
520
  		return ERR_PTR(-ENOTSUPP);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
521

472dbc45d   Johannes Berg   mac80211: split o...
522
  	if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0)
ae76eef02   Bob Copeland   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   Luis Carlos Cobo   mac80211: mesh pa...
539

402d7752e   Pavel Emelyanov   mac80211: Brush u...
540
  	err = -ENOMEM;
18889231e   Javier Cardona   mac80211: Move mp...
541
  	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
402d7752e   Pavel Emelyanov   mac80211: Brush u...
542
543
  	if (!new_mpath)
  		goto err_path_alloc;
18889231e   Javier Cardona   mac80211: Move mp...
544
  	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
402d7752e   Pavel Emelyanov   mac80211: Brush u...
545
546
  	if (!new_node)
  		goto err_node_alloc;
f84e71a94   Pavel Emelyanov   Fix GFP_KERNEL al...
547

eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
548
  	memcpy(new_mpath->dst, dst, ETH_ALEN);
e83e6541c   Johannes Berg   mac80211: use eth...
549
  	eth_broadcast_addr(new_mpath->rann_snd_addr);
35bcd5911   Chun-Yeow Yeoh   mac80211: fix the...
550
  	new_mpath->is_root = false;
f698d856f   Jasper Bryant-Greene   replace net_devic...
551
  	new_mpath->sdata = sdata;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
552
553
  	new_mpath->flags = 0;
  	skb_queue_head_init(&new_mpath->frame_queue);
eb2b9311f   Luis Carlos Cobo   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   Luis Carlos Cobo   mac80211: mesh pa...
560
  	hlist_add_head_rcu(&new_node->list, bucket);
349eb8cf4   Johannes Berg   mac80211: annotat...
561
562
  	if (atomic_inc_return(&tbl->entries) >=
  	    tbl->mean_chain_len * (tbl->hash_mask + 1))
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
563
  		grow = 1;
f5ea9120b   Johannes Berg   nl80211: add gene...
564
  	mesh_paths_generation++;
402d7752e   Pavel Emelyanov   mac80211: Brush u...
565
  	if (grow) {
18889231e   Javier Cardona   mac80211: Move mp...
566
  		set_bit(MESH_WORK_GROW_MPATH_TABLE,  &ifmsh->wrkq_flags);
64592c8fc   Johannes Berg   mac80211: use com...
567
  		ieee80211_queue_work(&local->hw, &sdata->work);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
568
  	}
ae76eef02   Bob Copeland   mac80211: return ...
569
570
  	mpath = new_mpath;
  found:
f06c7885c   Thomas Pedersen   mac80211: fix sma...
571
  	spin_unlock(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
572
  	read_unlock_bh(&pathtbl_resize_lock);
ae76eef02   Bob Copeland   mac80211: return ...
573
  	return mpath;
402d7752e   Pavel Emelyanov   mac80211: Brush u...
574
575
576
  err_node_alloc:
  	kfree(new_mpath);
  err_path_alloc:
472dbc45d   Johannes Berg   mac80211: split o...
577
  	atomic_dec(&sdata->u.mesh.mpaths);
ae76eef02   Bob Copeland   mac80211: return ...
578
579
580
  	spin_unlock(&tbl->hashwlock[hash_idx]);
  	read_unlock_bh(&pathtbl_resize_lock);
  	return ERR_PTR(err);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
581
  }
1928ecab6   Johannes Berg   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   Javier Cardona   mac80211: Move mp...
588
589
590
  void mesh_mpath_table_grow(void)
  {
  	struct mesh_table *oldtbl, *newtbl;
9b84b8089   Javier Cardona   mac80211: Fix loc...
591
  	write_lock_bh(&pathtbl_resize_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
592
593
  	oldtbl = resize_dereference_mesh_paths();
  	newtbl = mesh_table_alloc(oldtbl->size_order + 1);
1928ecab6   Johannes Berg   mac80211: fix and...
594
595
  	if (!newtbl)
  		goto out;
349eb8cf4   Johannes Berg   mac80211: annotat...
596
  	if (mesh_table_grow(oldtbl, newtbl) < 0) {
a3e6b12c0   cozybit Inc   mac80211: Allocat...
597
  		__mesh_table_free(newtbl);
1928ecab6   Johannes Berg   mac80211: fix and...
598
  		goto out;
18889231e   Javier Cardona   mac80211: Move mp...
599
600
  	}
  	rcu_assign_pointer(mesh_paths, newtbl);
18889231e   Javier Cardona   mac80211: Move mp...
601

1928ecab6   Johannes Berg   mac80211: fix and...
602
603
604
605
  	call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
  
   out:
  	write_unlock_bh(&pathtbl_resize_lock);
18889231e   Javier Cardona   mac80211: Move mp...
606
607
608
609
610
  }
  
  void mesh_mpp_table_grow(void)
  {
  	struct mesh_table *oldtbl, *newtbl;
9b84b8089   Javier Cardona   mac80211: Fix loc...
611
  	write_lock_bh(&pathtbl_resize_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
612
613
  	oldtbl = resize_dereference_mpp_paths();
  	newtbl = mesh_table_alloc(oldtbl->size_order + 1);
1928ecab6   Johannes Berg   mac80211: fix and...
614
615
  	if (!newtbl)
  		goto out;
349eb8cf4   Johannes Berg   mac80211: annotat...
616
  	if (mesh_table_grow(oldtbl, newtbl) < 0) {
a3e6b12c0   cozybit Inc   mac80211: Allocat...
617
  		__mesh_table_free(newtbl);
1928ecab6   Johannes Berg   mac80211: fix and...
618
  		goto out;
18889231e   Javier Cardona   mac80211: Move mp...
619
620
  	}
  	rcu_assign_pointer(mpp_paths, newtbl);
1928ecab6   Johannes Berg   mac80211: fix and...
621
  	call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
18889231e   Javier Cardona   mac80211: Move mp...
622

1928ecab6   Johannes Berg   mac80211: fix and...
623
624
   out:
  	write_unlock_bh(&pathtbl_resize_lock);
18889231e   Javier Cardona   mac80211: Move mp...
625
  }
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
626

bf7cd94dc   Johannes Berg   mac80211: clean u...
627
628
  int mpp_path_add(struct ieee80211_sub_if_data *sdata,
  		 const u8 *dst, const u8 *mpp)
79617deee   YanBo   mac80211: mesh po...
629
  {
18889231e   Javier Cardona   mac80211: Move mp...
630
631
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct ieee80211_local *local = sdata->local;
349eb8cf4   Johannes Berg   mac80211: annotat...
632
  	struct mesh_table *tbl;
79617deee   YanBo   mac80211: mesh po...
633
634
635
  	struct mesh_path *mpath, *new_mpath;
  	struct mpath_node *node, *new_node;
  	struct hlist_head *bucket;
79617deee   YanBo   mac80211: mesh po...
636
637
638
  	int grow = 0;
  	int err = 0;
  	u32 hash_idx;
b203ca391   Joe Perches   mac80211: Convert...
639
  	if (ether_addr_equal(dst, sdata->vif.addr))
79617deee   YanBo   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   Javier Cardona   mac80211: Move mp...
647
  	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
79617deee   YanBo   mac80211: mesh po...
648
649
  	if (!new_mpath)
  		goto err_path_alloc;
18889231e   Javier Cardona   mac80211: Move mp...
650
  	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
79617deee   YanBo   mac80211: mesh po...
651
652
  	if (!new_node)
  		goto err_node_alloc;
9b84b8089   Javier Cardona   mac80211: Fix loc...
653
  	read_lock_bh(&pathtbl_resize_lock);
79617deee   YanBo   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   Thomas Pedersen   mac80211: mesh ga...
660
  	init_timer(&new_mpath->timer);
79617deee   YanBo   mac80211: mesh po...
661
662
  	new_mpath->exp_time = jiffies;
  	spin_lock_init(&new_mpath->state_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
663
  	tbl = resize_dereference_mpp_paths();
79617deee   YanBo   mac80211: mesh po...
664

349eb8cf4   Johannes Berg   mac80211: annotat...
665
666
  	hash_idx = mesh_table_hash(dst, sdata, tbl);
  	bucket = &tbl->hash_buckets[hash_idx];
f06c7885c   Thomas Pedersen   mac80211: fix sma...
667
  	spin_lock(&tbl->hashwlock[hash_idx]);
79617deee   YanBo   mac80211: mesh po...
668
669
  
  	err = -EEXIST;
b67bfe0d4   Sasha Levin   hlist: drop the n...
670
  	hlist_for_each_entry(node, bucket, list) {
79617deee   YanBo   mac80211: mesh po...
671
  		mpath = node->mpath;
888d04dfb   Felix Fietkau   mac80211: use com...
672
  		if (mpath->sdata == sdata &&
b203ca391   Joe Perches   mac80211: Convert...
673
  		    ether_addr_equal(dst, mpath->dst))
79617deee   YanBo   mac80211: mesh po...
674
675
676
677
  			goto err_exists;
  	}
  
  	hlist_add_head_rcu(&new_node->list, bucket);
349eb8cf4   Johannes Berg   mac80211: annotat...
678
679
  	if (atomic_inc_return(&tbl->entries) >=
  	    tbl->mean_chain_len * (tbl->hash_mask + 1))
79617deee   YanBo   mac80211: mesh po...
680
  		grow = 1;
f06c7885c   Thomas Pedersen   mac80211: fix sma...
681
  	spin_unlock(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
682
  	read_unlock_bh(&pathtbl_resize_lock);
a2db2ed3f   Henning Rogge   mac80211: impleme...
683
684
  
  	mpp_paths_generation++;
79617deee   YanBo   mac80211: mesh po...
685
  	if (grow) {
18889231e   Javier Cardona   mac80211: Move mp...
686
  		set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
64592c8fc   Johannes Berg   mac80211: use com...
687
  		ieee80211_queue_work(&local->hw, &sdata->work);
79617deee   YanBo   mac80211: mesh po...
688
689
690
691
  	}
  	return 0;
  
  err_exists:
f06c7885c   Thomas Pedersen   mac80211: fix sma...
692
  	spin_unlock(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
693
  	read_unlock_bh(&pathtbl_resize_lock);
79617deee   YanBo   mac80211: mesh po...
694
695
696
697
698
699
  	kfree(new_node);
  err_node_alloc:
  	kfree(new_mpath);
  err_path_alloc:
  	return err;
  }
eb2b9311f   Luis Carlos Cobo   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   Johannes Berg   mac80211: annotat...
710
  	struct mesh_table *tbl;
15ff63653   Johannes Berg   mac80211: use fix...
711
  	static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
712
713
  	struct mesh_path *mpath;
  	struct mpath_node *node;
f698d856f   Jasper Bryant-Greene   replace net_devic...
714
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
715
716
717
  	int i;
  
  	rcu_read_lock();
349eb8cf4   Johannes Berg   mac80211: annotat...
718
  	tbl = rcu_dereference(mesh_paths);
b67bfe0d4   Sasha Levin   hlist: drop the n...
719
  	for_each_mesh_entry(tbl, node, i) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
720
  		mpath = node->mpath;
2688eba9d   Andreea-Cristina Bernat   mac80211: Replace...
721
  		if (rcu_access_pointer(mpath->next_hop) == sta &&
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
722
723
  		    mpath->flags & MESH_PATH_ACTIVE &&
  		    !(mpath->flags & MESH_PATH_FIXED)) {
f5e50cd07   Javier Cardona   mac80211: Improve...
724
  			spin_lock_bh(&mpath->state_lock);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
725
  			mpath->flags &= ~MESH_PATH_ACTIVE;
d19b3bf63   Rui Paulo   mac80211: replace...
726
  			++mpath->sn;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
727
  			spin_unlock_bh(&mpath->state_lock);
bf7cd94dc   Johannes Berg   mac80211: clean u...
728
  			mesh_path_error_tx(sdata,
f63f8421d   Chun-Yeow Yeoh   mac80211: use put...
729
730
731
  				sdata->u.mesh.mshcfg.element_ttl,
  				mpath->dst, mpath->sn,
  				WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
f5e50cd07   Javier Cardona   mac80211: Improve...
732
  		}
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
733
734
735
  	}
  	rcu_read_unlock();
  }
19c50b3dc   Javier Cardona   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   Luis Carlos Cobo   mac80211: mesh pa...
761
762
763
  /**
   * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
   *
2c53040f0   Ben Hutchings   net: Fix (nearly-...
764
   * @sta: mesh peer to match
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
765
   *
b4e08ea14   Luis Carlos Cobo   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   Johannes Berg   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   Luis Carlos Cobo   mac80211: mesh pa...
771
772
773
   */
  void mesh_path_flush_by_nexthop(struct sta_info *sta)
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
774
  	struct mesh_table *tbl;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
775
776
  	struct mesh_path *mpath;
  	struct mpath_node *node;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
777
  	int i;
349eb8cf4   Johannes Berg   mac80211: annotat...
778
  	rcu_read_lock();
239289e44   Javier Cardona   mac80211: Consoli...
779
780
  	read_lock_bh(&pathtbl_resize_lock);
  	tbl = resize_dereference_mesh_paths();
b67bfe0d4   Sasha Levin   hlist: drop the n...
781
  	for_each_mesh_entry(tbl, node, i) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
782
  		mpath = node->mpath;
2688eba9d   Andreea-Cristina Bernat   mac80211: Replace...
783
  		if (rcu_access_pointer(mpath->next_hop) == sta) {
f06c7885c   Thomas Pedersen   mac80211: fix sma...
784
  			spin_lock(&tbl->hashwlock[i]);
19c50b3dc   Javier Cardona   mac80211: Don't i...
785
  			__mesh_path_del(tbl, node);
f06c7885c   Thomas Pedersen   mac80211: fix sma...
786
  			spin_unlock(&tbl->hashwlock[i]);
19c50b3dc   Javier Cardona   mac80211: Don't i...
787
  		}
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
788
  	}
239289e44   Javier Cardona   mac80211: Consoli...
789
  	read_unlock_bh(&pathtbl_resize_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
790
  	rcu_read_unlock();
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
791
  }
cd72e8174   Javier Cardona   mac80211: Consoli...
792
793
  static void table_flush_by_iface(struct mesh_table *tbl,
  				 struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
794
795
796
  {
  	struct mesh_path *mpath;
  	struct mpath_node *node;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
797
  	int i;
cd72e8174   Javier Cardona   mac80211: Consoli...
798
  	WARN_ON(!rcu_read_lock_held());
b67bfe0d4   Sasha Levin   hlist: drop the n...
799
  	for_each_mesh_entry(tbl, node, i) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
800
  		mpath = node->mpath;
cd72e8174   Javier Cardona   mac80211: Consoli...
801
802
  		if (mpath->sdata != sdata)
  			continue;
ece1a2e7e   Javier Cardona   mac80211: Remove ...
803
  		spin_lock_bh(&tbl->hashwlock[i]);
19c50b3dc   Javier Cardona   mac80211: Don't i...
804
  		__mesh_path_del(tbl, node);
ece1a2e7e   Javier Cardona   mac80211: Remove ...
805
  		spin_unlock_bh(&tbl->hashwlock[i]);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
806
807
  	}
  }
ece1a2e7e   Javier Cardona   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   Ben Hutchings   net: Fix (nearly-...
813
   * @sdata: interface data to match
ece1a2e7e   Javier Cardona   mac80211: Remove ...
814
815
816
   *
   */
  void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
817
  {
cd72e8174   Javier Cardona   mac80211: Consoli...
818
  	struct mesh_table *tbl;
d0709a651   Johannes Berg   mac80211: RCU-ify...
819

cd72e8174   Javier Cardona   mac80211: Consoli...
820
  	rcu_read_lock();
239289e44   Javier Cardona   mac80211: Consoli...
821
822
  	read_lock_bh(&pathtbl_resize_lock);
  	tbl = resize_dereference_mesh_paths();
cd72e8174   Javier Cardona   mac80211: Consoli...
823
  	table_flush_by_iface(tbl, sdata);
239289e44   Javier Cardona   mac80211: Consoli...
824
  	tbl = resize_dereference_mpp_paths();
cd72e8174   Javier Cardona   mac80211: Consoli...
825
  	table_flush_by_iface(tbl, sdata);
239289e44   Javier Cardona   mac80211: Consoli...
826
  	read_unlock_bh(&pathtbl_resize_lock);
cd72e8174   Javier Cardona   mac80211: Consoli...
827
  	rcu_read_unlock();
eb2b9311f   Luis Carlos Cobo   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   Jasper Bryant-Greene   replace net_devic...
834
   * @sdata: local subif
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
835
   *
af901ca18   André Goddard Rosa   tree-wide: fix as...
836
   * Returns: 0 if successful
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
837
   */
bf7cd94dc   Johannes Berg   mac80211: clean u...
838
  int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
839
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
840
  	struct mesh_table *tbl;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
841
842
843
  	struct mesh_path *mpath;
  	struct mpath_node *node;
  	struct hlist_head *bucket;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
844
845
  	int hash_idx;
  	int err = 0;
9b84b8089   Javier Cardona   mac80211: Fix loc...
846
  	read_lock_bh(&pathtbl_resize_lock);
349eb8cf4   Johannes Berg   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   Luis Carlos Cobo   mac80211: mesh pa...
850

f06c7885c   Thomas Pedersen   mac80211: fix sma...
851
  	spin_lock(&tbl->hashwlock[hash_idx]);
b67bfe0d4   Sasha Levin   hlist: drop the n...
852
  	hlist_for_each_entry(node, bucket, list) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
853
  		mpath = node->mpath;
f698d856f   Jasper Bryant-Greene   replace net_devic...
854
  		if (mpath->sdata == sdata &&
b203ca391   Joe Perches   mac80211: Convert...
855
  		    ether_addr_equal(addr, mpath->dst)) {
19c50b3dc   Javier Cardona   mac80211: Don't i...
856
  			__mesh_path_del(tbl, node);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
857
858
859
860
861
862
  			goto enddel;
  		}
  	}
  
  	err = -ENXIO;
  enddel:
f5ea9120b   Johannes Berg   nl80211: add gene...
863
  	mesh_paths_generation++;
f06c7885c   Thomas Pedersen   mac80211: fix sma...
864
  	spin_unlock(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
865
  	read_unlock_bh(&pathtbl_resize_lock);
eb2b9311f   Luis Carlos Cobo   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   Javier Cardona   mac80211: Fix reg...
879
880
881
  	if (mpath->flags & MESH_PATH_ACTIVE)
  		ieee80211_add_pending_skbs(mpath->sdata->local,
  				&mpath->frame_queue);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
882
883
884
  }
  
  /**
5ee68e5b3   Javier Cardona   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   Javier Cardona   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   Sasha Levin   hlist: drop the n...
910
  	hlist_for_each_entry_rcu(gate, known_gates, list) {
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
911
912
913
914
  		if (gate->mpath->sdata != sdata)
  			continue;
  
  		if (gate->mpath->flags & MESH_PATH_ACTIVE) {
bdcbd8e0e   Johannes Berg   mac80211: clean u...
915
916
  			mpath_dbg(sdata, "Forwarding to %pM
  ", gate->mpath->dst);
5ee68e5b3   Javier Cardona   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   Johannes Berg   mac80211: clean u...
921
922
923
924
  			mpath_dbg(sdata,
  				  "Not forwarding %p (flags %#x)
  ",
  				  gate->mpath, gate->mpath->flags);
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
925
926
  		}
  	}
b67bfe0d4   Sasha Levin   hlist: drop the n...
927
  	hlist_for_each_entry_rcu(gate, known_gates, list)
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
928
  		if (gate->mpath->sdata == sdata) {
bdcbd8e0e   Johannes Berg   mac80211: clean u...
929
930
  			mpath_dbg(sdata, "Sending to %pM
  ", gate->mpath->dst);
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
931
932
933
934
935
936
937
  			mesh_path_tx_pending(gate->mpath);
  		}
  
  	return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
  }
  
  /**
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
938
939
940
   * mesh_path_discard_frame - discard a frame whose path could not be resolved
   *
   * @skb: frame to discard
f698d856f   Jasper Bryant-Greene   replace net_devic...
941
   * @sdata: network subif the frame was to be sent through
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
942
   *
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
943
944
   * Locking: the function must me called within a rcu_read_lock region
   */
bf7cd94dc   Johannes Berg   mac80211: clean u...
945
946
  void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
  			     struct sk_buff *skb)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
947
  {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
948
  	kfree_skb(skb);
472dbc45d   Johannes Berg   mac80211: split o...
949
  	sdata->u.mesh.mshstats.dropped_frames_no_route++;
eb2b9311f   Luis Carlos Cobo   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   Lucas De Marchi   Fix common misspe...
957
   * Locking: the function must me called within a rcu_read_lock region
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
958
959
960
   */
  void mesh_path_flush_pending(struct mesh_path *mpath)
  {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
961
  	struct sk_buff *skb;
00e3f25c8   Javier Cardona   mac80211: fix mes...
962
  	while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
bf7cd94dc   Johannes Berg   mac80211: clean u...
963
  		mesh_path_discard_frame(mpath->sdata, skb);
eb2b9311f   Luis Carlos Cobo   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   Rui Paulo   mac80211: replace...
978
  	mpath->sn = 0xffff;
eb2b9311f   Luis Carlos Cobo   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   Javier Cardona   mac80211: Deactiv...
994
995
  	if (free_leafs) {
  		del_timer_sync(&mpath->timer);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
996
  		kfree(mpath);
d0df9eecf   Javier Cardona   mac80211: Deactiv...
997
  	}
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
998
999
  	kfree(node);
  }
4caf86c69   Pavel Emelyanov   mac80211: Prepare...
1000
  static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1001
1002
1003
1004
  {
  	struct mesh_path *mpath;
  	struct mpath_node *node, *new_node;
  	u32 hash_idx;
8566dc3fc   Pavel Emelyanov   mac80211: Fix sle...
1005
  	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
00242c40a   Pavel Emelyanov   mac80211: Report ...
1006
1007
  	if (new_node == NULL)
  		return -ENOMEM;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1008
1009
  	node = hlist_entry(p, struct mpath_node, list);
  	mpath = node->mpath;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1010
  	new_node->mpath = mpath;
f698d856f   Jasper Bryant-Greene   replace net_devic...
1011
  	hash_idx = mesh_table_hash(mpath->dst, mpath->sdata, newtbl);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1012
1013
  	hlist_add_head(&new_node->list,
  			&newtbl->hash_buckets[hash_idx]);
4caf86c69   Pavel Emelyanov   mac80211: Prepare...
1014
  	return 0;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1015
1016
1017
1018
  }
  
  int mesh_pathtbl_init(void)
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
1019
  	struct mesh_table *tbl_path, *tbl_mpp;
4c5ade414   Dan Carpenter   mac80211: handle ...
1020
  	int ret;
349eb8cf4   Johannes Berg   mac80211: annotat...
1021
1022
1023
  
  	tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
  	if (!tbl_path)
79617deee   YanBo   mac80211: mesh po...
1024
  		return -ENOMEM;
349eb8cf4   Johannes Berg   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   Javier Cardona   mac80211: mesh ga...
1028
  	tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
4c5ade414   Dan Carpenter   mac80211: handle ...
1029
1030
1031
1032
  	if (!tbl_path->known_gates) {
  		ret = -ENOMEM;
  		goto free_path;
  	}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1033
  	INIT_HLIST_HEAD(tbl_path->known_gates);
79617deee   YanBo   mac80211: mesh po...
1034

349eb8cf4   Johannes Berg   mac80211: annotat...
1035
1036
  	tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
  	if (!tbl_mpp) {
4c5ade414   Dan Carpenter   mac80211: handle ...
1037
1038
  		ret = -ENOMEM;
  		goto free_path;
79617deee   YanBo   mac80211: mesh po...
1039
  	}
349eb8cf4   Johannes Berg   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   Javier Cardona   mac80211: mesh ga...
1043
  	tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
4c5ade414   Dan Carpenter   mac80211: handle ...
1044
1045
1046
1047
  	if (!tbl_mpp->known_gates) {
  		ret = -ENOMEM;
  		goto free_mpp;
  	}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1048
  	INIT_HLIST_HEAD(tbl_mpp->known_gates);
349eb8cf4   Johannes Berg   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   YanBo   mac80211: mesh po...
1053

eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1054
  	return 0;
4c5ade414   Dan Carpenter   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   Luis Carlos Cobo   mac80211: mesh pa...
1061
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
1062
  void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1063
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
1064
  	struct mesh_table *tbl;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1065
1066
  	struct mesh_path *mpath;
  	struct mpath_node *node;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1067
  	int i;
349eb8cf4   Johannes Berg   mac80211: annotat...
1068
1069
  	rcu_read_lock();
  	tbl = rcu_dereference(mesh_paths);
b67bfe0d4   Sasha Levin   hlist: drop the n...
1070
  	for_each_mesh_entry(tbl, node, i) {
f698d856f   Jasper Bryant-Greene   replace net_devic...
1071
  		if (node->mpath->sdata != sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1072
1073
  			continue;
  		mpath = node->mpath;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1074
1075
  		if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
  		    (!(mpath->flags & MESH_PATH_FIXED)) &&
f5e50cd07   Javier Cardona   mac80211: Improve...
1076
  		     time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
bf7cd94dc   Johannes Berg   mac80211: clean u...
1077
  			mesh_path_del(mpath->sdata, mpath->dst);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1078
  	}
349eb8cf4   Johannes Berg   mac80211: annotat...
1079
  	rcu_read_unlock();
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1080
1081
1082
1083
  }
  
  void mesh_pathtbl_unregister(void)
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
1084
  	/* no need for locking during exit path */
33d480ce6   Eric Dumazet   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   Luis Carlos Cobo   mac80211: mesh pa...
1087
  }