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
  #include "ieee80211_i.h"
  #include "mesh.h"
7646887a5   Javier Cardona   mac80211: improve...
20
21
22
23
24
  #ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
  #define mpath_dbg(fmt, args...)	printk(KERN_DEBUG fmt, ##args)
  #else
  #define mpath_dbg(fmt, args...)	do { (void)(0); } while (0)
  #endif
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  /* 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
  
  #define MPATH_EXPIRED(mpath) ((mpath->flags & MESH_PATH_ACTIVE) && \
  				time_after(jiffies, mpath->exp_time) && \
  				!(mpath->flags & MESH_PATH_FIXED))
  
  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...
43
44
  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...
45

f5ea9120b   Johannes Berg   nl80211: add gene...
46
  int mesh_paths_generation;
6b86bd62a   Johannes Berg   mac80211: mesh: m...
47
48
  
  /* This lock will have the grow table function as writer and add / delete nodes
239289e44   Javier Cardona   mac80211: Consoli...
49
50
51
52
   * 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...
53
54
   */
  static DEFINE_RWLOCK(pathtbl_resize_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  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(...), ...)
   */
  #define for_each_mesh_entry(tbl, p, node, i) \
  	for (i = 0; i <= tbl->hash_mask; i++) \
  		hlist_for_each_entry_rcu(node, p, &tbl->hash_buckets[i], list)
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
135
136
137
138
139
140
141
142
  	if (free_leafs) {
  		spin_lock_bh(&tbl->gates_lock);
  		hlist_for_each_entry_safe(gate, p, q,
  					 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
  }
6b86bd62a   Johannes Berg   mac80211: mesh: m...
175
176
177
178
179
180
181
  static u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
  			   struct mesh_table *tbl)
  {
  	/* Use last four bytes of hw addr and interface index as hash index */
  	return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd)
  		& tbl->hash_mask;
  }
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
197
198
  	struct sk_buff *skb;
  	struct ieee80211_hdr *hdr;
  	struct sk_buff_head tmpq;
  	unsigned long flags;
d0709a651   Johannes Berg   mac80211: RCU-ify...
199
  	rcu_assign_pointer(mpath->next_hop, sta);
10c836d78   Javier Cardona   mac80211: Assign ...
200
201
202
203
204
205
206
207
  
  	__skb_queue_head_init(&tmpq);
  
  	spin_lock_irqsave(&mpath->frame_queue.lock, flags);
  
  	while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
  		hdr = (struct ieee80211_hdr *) skb->data;
  		memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
7e3c88660   Thomas Pedersen   mac80211: failed ...
208
  		memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN);
10c836d78   Javier Cardona   mac80211: Assign ...
209
210
211
212
213
  		__skb_queue_tail(&tmpq, skb);
  	}
  
  	skb_queue_splice(&tmpq, &mpath->frame_queue);
  	spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
214
  }
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
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
245
246
247
248
249
250
  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 ...
251
  	memcpy(hdr->addr2, gate_mpath->sdata->vif.addr, ETH_ALEN);
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  	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)
  {
c61336611   Thomas Pedersen   mac80211: mesh ga...
277
  	struct sk_buff *skb, *cp_skb = NULL;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  	struct sk_buff_head gateq, failq;
  	unsigned long flags;
  	int num_skbs;
  
  	BUG_ON(gate_mpath == from_mpath);
  	BUG_ON(!gate_mpath->next_hop);
  
  	__skb_queue_head_init(&gateq);
  	__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);
  
  	num_skbs = skb_queue_len(&failq);
  
  	while (num_skbs--) {
  		skb = __skb_dequeue(&failq);
817a53d98   John W. Linville   mac80211: refacto...
296
  		if (copy) {
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
297
  			cp_skb = skb_copy(skb, GFP_ATOMIC);
817a53d98   John W. Linville   mac80211: refacto...
298
299
300
  			if (cp_skb)
  				__skb_queue_tail(&failq, cp_skb);
  		}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
301
302
303
  
  		prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
  		__skb_queue_tail(&gateq, skb);
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
  	}
  
  	spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags);
  	skb_queue_splice(&gateq, &gate_mpath->frame_queue);
  	mpath_dbg("Mpath queue for gate %pM has %d frames
  ",
  			gate_mpath->dst,
  			skb_queue_len(&gate_mpath->frame_queue));
  	spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags);
  
  	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...
321

239289e44   Javier Cardona   mac80211: Consoli...
322
323
  static struct mesh_path *path_lookup(struct mesh_table *tbl, u8 *dst,
  					  struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
324
325
326
327
  {
  	struct mesh_path *mpath;
  	struct hlist_node *n;
  	struct hlist_head *bucket;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
328
  	struct mpath_node *node;
f698d856f   Jasper Bryant-Greene   replace net_devic...
329
  	bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
330
331
  	hlist_for_each_entry_rcu(node, n, bucket, list) {
  		mpath = node->mpath;
f698d856f   Jasper Bryant-Greene   replace net_devic...
332
  		if (mpath->sdata == sdata &&
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
333
334
335
  				memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
  			if (MPATH_EXPIRED(mpath)) {
  				spin_lock_bh(&mpath->state_lock);
ad99d1411   Javier Cardona   mac80211: Remove ...
336
  				mpath->flags &= ~MESH_PATH_ACTIVE;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
337
338
339
340
341
342
343
  				spin_unlock_bh(&mpath->state_lock);
  			}
  			return mpath;
  		}
  	}
  	return NULL;
  }
239289e44   Javier Cardona   mac80211: Consoli...
344
345
346
347
348
349
350
351
352
353
  /**
   * mesh_path_lookup - look up a path in the mesh path table
   * @dst: hardware address (ETH_ALEN length) of destination
   * @sdata: local subif
   *
   * Returns: pointer to the mesh path structure, or NULL if not found
   *
   * Locking: must be called within a read rcu section.
   */
  struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
79617deee   YanBo   mac80211: mesh po...
354
  {
239289e44   Javier Cardona   mac80211: Consoli...
355
356
  	return path_lookup(rcu_dereference(mesh_paths), dst, sdata);
  }
79617deee   YanBo   mac80211: mesh po...
357

239289e44   Javier Cardona   mac80211: Consoli...
358
359
360
  struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
  {
  	return path_lookup(rcu_dereference(mpp_paths), dst, sdata);
79617deee   YanBo   mac80211: mesh po...
361
  }
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
362
363
364
  /**
   * 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...
365
   * @sdata: local subif, or NULL for all entries
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
366
367
368
369
370
   *
   * Returns: pointer to the mesh path structure, or NULL if not found.
   *
   * Locking: must be called within a read rcu section.
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
371
  struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
372
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
373
  	struct mesh_table *tbl = rcu_dereference(mesh_paths);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
374
375
376
377
  	struct mpath_node *node;
  	struct hlist_node *p;
  	int i;
  	int j = 0;
349eb8cf4   Johannes Berg   mac80211: annotat...
378
  	for_each_mesh_entry(tbl, p, node, i) {
f698d856f   Jasper Bryant-Greene   replace net_devic...
379
  		if (sdata && node->mpath->sdata != sdata)
2a8ca29a8   Luis Carlos Cobo   mac80211: fix mes...
380
  			continue;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
381
382
383
  		if (j++ == idx) {
  			if (MPATH_EXPIRED(node->mpath)) {
  				spin_lock_bh(&node->mpath->state_lock);
ad99d1411   Javier Cardona   mac80211: Remove ...
384
  				node->mpath->flags &= ~MESH_PATH_ACTIVE;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
385
386
387
388
  				spin_unlock_bh(&node->mpath->state_lock);
  			}
  			return node->mpath;
  		}
2a8ca29a8   Luis Carlos Cobo   mac80211: fix mes...
389
  	}
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
390
391
392
  
  	return NULL;
  }
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
393
394
395
396
397
398
399
  static void mesh_gate_node_reclaim(struct rcu_head *rp)
  {
  	struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
  	kfree(node);
  }
  
  /**
30be52e44   Johannes Berg   mac80211: fix RCU...
400
401
   * 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...
402
   */
30be52e44   Johannes Berg   mac80211: fix RCU...
403
  int mesh_path_add_gate(struct mesh_path *mpath)
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
404
  {
30be52e44   Johannes Berg   mac80211: fix RCU...
405
  	struct mesh_table *tbl;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
406
407
408
409
410
  	struct mpath_node *gate, *new_gate;
  	struct hlist_node *n;
  	int err;
  
  	rcu_read_lock();
30be52e44   Johannes Berg   mac80211: fix RCU...
411
  	tbl = rcu_dereference(mesh_paths);
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
  
  	hlist_for_each_entry_rcu(gate, n, tbl->known_gates, list)
  		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);
  	rcu_read_unlock();
  	mpath_dbg("Mesh path (%s): Recorded new gate: %pM. %d known gates
  ",
  		  mpath->sdata->name, mpath->dst,
  		  mpath->sdata->u.mesh.num_gates);
  	return 0;
  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
   *
   * Returns: 0 on success
   *
   * Locking: must be called inside rcu_read_lock() section
   */
  static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
  {
  	struct mpath_node *gate;
  	struct hlist_node *p, *q;
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  	hlist_for_each_entry_safe(gate, p, q, tbl->known_gates, list)
  		if (gate->mpath == mpath) {
  			spin_lock_bh(&tbl->gates_lock);
  			hlist_del_rcu(&gate->list);
  			call_rcu(&gate->rcu, mesh_gate_node_reclaim);
  			spin_unlock_bh(&tbl->gates_lock);
  			mpath->sdata->u.mesh.num_gates--;
  			mpath->is_gate = false;
  			mpath_dbg("Mesh path (%s): Deleted gate: %pM. "
  				  "%d known gates
  ", mpath->sdata->name,
  				  mpath->dst, mpath->sdata->u.mesh.num_gates);
  			break;
  		}
  
  	return 0;
  }
  
  /**
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
474
475
476
477
478
479
480
   * 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...
481
482
483
  /**
   * mesh_path_add - allocate and add a new path to the mesh path table
   * @addr: destination address of the path (ETH_ALEN length)
f698d856f   Jasper Bryant-Greene   replace net_devic...
484
   * @sdata: local subif
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
485
   *
af901ca18   André Goddard Rosa   tree-wide: fix as...
486
   * Returns: 0 on success
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
487
488
489
   *
   * State: the initial state of the new path is set to 0
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
490
  int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
491
  {
18889231e   Javier Cardona   mac80211: Move mp...
492
493
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct ieee80211_local *local = sdata->local;
349eb8cf4   Johannes Berg   mac80211: annotat...
494
  	struct mesh_table *tbl;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
495
496
497
498
499
500
501
  	struct mesh_path *mpath, *new_mpath;
  	struct mpath_node *node, *new_node;
  	struct hlist_head *bucket;
  	struct hlist_node *n;
  	int grow = 0;
  	int err = 0;
  	u32 hash_idx;
47846c9b0   Johannes Berg   mac80211: reduce ...
502
  	if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
503
504
505
506
507
  		/* never add ourselves as neighbours */
  		return -ENOTSUPP;
  
  	if (is_multicast_ether_addr(dst))
  		return -ENOTSUPP;
472dbc45d   Johannes Berg   mac80211: split o...
508
  	if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
509
  		return -ENOSPC;
402d7752e   Pavel Emelyanov   mac80211: Brush u...
510
  	err = -ENOMEM;
18889231e   Javier Cardona   mac80211: Move mp...
511
  	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
402d7752e   Pavel Emelyanov   mac80211: Brush u...
512
513
  	if (!new_mpath)
  		goto err_path_alloc;
18889231e   Javier Cardona   mac80211: Move mp...
514
  	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
402d7752e   Pavel Emelyanov   mac80211: Brush u...
515
516
  	if (!new_node)
  		goto err_node_alloc;
f84e71a94   Pavel Emelyanov   Fix GFP_KERNEL al...
517

9b84b8089   Javier Cardona   mac80211: Fix loc...
518
  	read_lock_bh(&pathtbl_resize_lock);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
519
  	memcpy(new_mpath->dst, dst, ETH_ALEN);
f698d856f   Jasper Bryant-Greene   replace net_devic...
520
  	new_mpath->sdata = sdata;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
521
522
  	new_mpath->flags = 0;
  	skb_queue_head_init(&new_mpath->frame_queue);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
523
524
525
526
527
528
  	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);
349eb8cf4   Johannes Berg   mac80211: annotat...
529
  	tbl = resize_dereference_mesh_paths();
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
530

349eb8cf4   Johannes Berg   mac80211: annotat...
531
532
  	hash_idx = mesh_table_hash(dst, sdata, tbl);
  	bucket = &tbl->hash_buckets[hash_idx];
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
533

349eb8cf4   Johannes Berg   mac80211: annotat...
534
  	spin_lock_bh(&tbl->hashwlock[hash_idx]);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
535

402d7752e   Pavel Emelyanov   mac80211: Brush u...
536
  	err = -EEXIST;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
537
538
  	hlist_for_each_entry(node, n, bucket, list) {
  		mpath = node->mpath;
f698d856f   Jasper Bryant-Greene   replace net_devic...
539
  		if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
402d7752e   Pavel Emelyanov   mac80211: Brush u...
540
  			goto err_exists;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
541
542
543
  	}
  
  	hlist_add_head_rcu(&new_node->list, bucket);
349eb8cf4   Johannes Berg   mac80211: annotat...
544
545
  	if (atomic_inc_return(&tbl->entries) >=
  	    tbl->mean_chain_len * (tbl->hash_mask + 1))
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
546
  		grow = 1;
f5ea9120b   Johannes Berg   nl80211: add gene...
547
  	mesh_paths_generation++;
349eb8cf4   Johannes Berg   mac80211: annotat...
548
  	spin_unlock_bh(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
549
  	read_unlock_bh(&pathtbl_resize_lock);
402d7752e   Pavel Emelyanov   mac80211: Brush u...
550
  	if (grow) {
18889231e   Javier Cardona   mac80211: Move mp...
551
  		set_bit(MESH_WORK_GROW_MPATH_TABLE,  &ifmsh->wrkq_flags);
64592c8fc   Johannes Berg   mac80211: use com...
552
  		ieee80211_queue_work(&local->hw, &sdata->work);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
553
  	}
402d7752e   Pavel Emelyanov   mac80211: Brush u...
554
555
556
  	return 0;
  
  err_exists:
349eb8cf4   Johannes Berg   mac80211: annotat...
557
  	spin_unlock_bh(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
558
  	read_unlock_bh(&pathtbl_resize_lock);
402d7752e   Pavel Emelyanov   mac80211: Brush u...
559
560
561
562
  	kfree(new_node);
  err_node_alloc:
  	kfree(new_mpath);
  err_path_alloc:
472dbc45d   Johannes Berg   mac80211: split o...
563
  	atomic_dec(&sdata->u.mesh.mpaths);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
564
565
  	return err;
  }
1928ecab6   Johannes Berg   mac80211: fix and...
566
567
568
569
570
571
  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...
572
573
574
  void mesh_mpath_table_grow(void)
  {
  	struct mesh_table *oldtbl, *newtbl;
9b84b8089   Javier Cardona   mac80211: Fix loc...
575
  	write_lock_bh(&pathtbl_resize_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
576
577
  	oldtbl = resize_dereference_mesh_paths();
  	newtbl = mesh_table_alloc(oldtbl->size_order + 1);
1928ecab6   Johannes Berg   mac80211: fix and...
578
579
  	if (!newtbl)
  		goto out;
349eb8cf4   Johannes Berg   mac80211: annotat...
580
  	if (mesh_table_grow(oldtbl, newtbl) < 0) {
a3e6b12c0   cozybit Inc   mac80211: Allocat...
581
  		__mesh_table_free(newtbl);
1928ecab6   Johannes Berg   mac80211: fix and...
582
  		goto out;
18889231e   Javier Cardona   mac80211: Move mp...
583
584
  	}
  	rcu_assign_pointer(mesh_paths, newtbl);
18889231e   Javier Cardona   mac80211: Move mp...
585

1928ecab6   Johannes Berg   mac80211: fix and...
586
587
588
589
  	call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
  
   out:
  	write_unlock_bh(&pathtbl_resize_lock);
18889231e   Javier Cardona   mac80211: Move mp...
590
591
592
593
594
  }
  
  void mesh_mpp_table_grow(void)
  {
  	struct mesh_table *oldtbl, *newtbl;
9b84b8089   Javier Cardona   mac80211: Fix loc...
595
  	write_lock_bh(&pathtbl_resize_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
596
597
  	oldtbl = resize_dereference_mpp_paths();
  	newtbl = mesh_table_alloc(oldtbl->size_order + 1);
1928ecab6   Johannes Berg   mac80211: fix and...
598
599
  	if (!newtbl)
  		goto out;
349eb8cf4   Johannes Berg   mac80211: annotat...
600
  	if (mesh_table_grow(oldtbl, newtbl) < 0) {
a3e6b12c0   cozybit Inc   mac80211: Allocat...
601
  		__mesh_table_free(newtbl);
1928ecab6   Johannes Berg   mac80211: fix and...
602
  		goto out;
18889231e   Javier Cardona   mac80211: Move mp...
603
604
  	}
  	rcu_assign_pointer(mpp_paths, newtbl);
1928ecab6   Johannes Berg   mac80211: fix and...
605
  	call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
18889231e   Javier Cardona   mac80211: Move mp...
606

1928ecab6   Johannes Berg   mac80211: fix and...
607
608
   out:
  	write_unlock_bh(&pathtbl_resize_lock);
18889231e   Javier Cardona   mac80211: Move mp...
609
  }
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
610

79617deee   YanBo   mac80211: mesh po...
611
612
  int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
  {
18889231e   Javier Cardona   mac80211: Move mp...
613
614
  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
  	struct ieee80211_local *local = sdata->local;
349eb8cf4   Johannes Berg   mac80211: annotat...
615
  	struct mesh_table *tbl;
79617deee   YanBo   mac80211: mesh po...
616
617
618
619
620
621
622
  	struct mesh_path *mpath, *new_mpath;
  	struct mpath_node *node, *new_node;
  	struct hlist_head *bucket;
  	struct hlist_node *n;
  	int grow = 0;
  	int err = 0;
  	u32 hash_idx;
47846c9b0   Johannes Berg   mac80211: reduce ...
623
  	if (memcmp(dst, sdata->vif.addr, ETH_ALEN) == 0)
79617deee   YanBo   mac80211: mesh po...
624
625
626
627
628
629
630
  		/* never add ourselves as neighbours */
  		return -ENOTSUPP;
  
  	if (is_multicast_ether_addr(dst))
  		return -ENOTSUPP;
  
  	err = -ENOMEM;
18889231e   Javier Cardona   mac80211: Move mp...
631
  	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
79617deee   YanBo   mac80211: mesh po...
632
633
  	if (!new_mpath)
  		goto err_path_alloc;
18889231e   Javier Cardona   mac80211: Move mp...
634
  	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
79617deee   YanBo   mac80211: mesh po...
635
636
  	if (!new_node)
  		goto err_node_alloc;
9b84b8089   Javier Cardona   mac80211: Fix loc...
637
  	read_lock_bh(&pathtbl_resize_lock);
79617deee   YanBo   mac80211: mesh po...
638
639
640
641
642
643
  	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...
644
  	init_timer(&new_mpath->timer);
79617deee   YanBo   mac80211: mesh po...
645
646
  	new_mpath->exp_time = jiffies;
  	spin_lock_init(&new_mpath->state_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
647
  	tbl = resize_dereference_mpp_paths();
79617deee   YanBo   mac80211: mesh po...
648

349eb8cf4   Johannes Berg   mac80211: annotat...
649
650
651
652
  	hash_idx = mesh_table_hash(dst, sdata, tbl);
  	bucket = &tbl->hash_buckets[hash_idx];
  
  	spin_lock_bh(&tbl->hashwlock[hash_idx]);
79617deee   YanBo   mac80211: mesh po...
653
654
655
656
657
658
659
660
661
  
  	err = -EEXIST;
  	hlist_for_each_entry(node, n, bucket, list) {
  		mpath = node->mpath;
  		if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
  			goto err_exists;
  	}
  
  	hlist_add_head_rcu(&new_node->list, bucket);
349eb8cf4   Johannes Berg   mac80211: annotat...
662
663
  	if (atomic_inc_return(&tbl->entries) >=
  	    tbl->mean_chain_len * (tbl->hash_mask + 1))
79617deee   YanBo   mac80211: mesh po...
664
  		grow = 1;
349eb8cf4   Johannes Berg   mac80211: annotat...
665
  	spin_unlock_bh(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
666
  	read_unlock_bh(&pathtbl_resize_lock);
79617deee   YanBo   mac80211: mesh po...
667
  	if (grow) {
18889231e   Javier Cardona   mac80211: Move mp...
668
  		set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
64592c8fc   Johannes Berg   mac80211: use com...
669
  		ieee80211_queue_work(&local->hw, &sdata->work);
79617deee   YanBo   mac80211: mesh po...
670
671
672
673
  	}
  	return 0;
  
  err_exists:
349eb8cf4   Johannes Berg   mac80211: annotat...
674
  	spin_unlock_bh(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
675
  	read_unlock_bh(&pathtbl_resize_lock);
79617deee   YanBo   mac80211: mesh po...
676
677
678
679
680
681
  	kfree(new_node);
  err_node_alloc:
  	kfree(new_mpath);
  err_path_alloc:
  	return err;
  }
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
682
683
684
685
686
687
688
689
690
691
  /**
   * 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...
692
  	struct mesh_table *tbl;
15ff63653   Johannes Berg   mac80211: use fix...
693
  	static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
694
695
696
  	struct mesh_path *mpath;
  	struct mpath_node *node;
  	struct hlist_node *p;
f698d856f   Jasper Bryant-Greene   replace net_devic...
697
  	struct ieee80211_sub_if_data *sdata = sta->sdata;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
698
  	int i;
25d49e4d6   Thomas Pedersen   mac80211: update ...
699
  	__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
700
701
  
  	rcu_read_lock();
349eb8cf4   Johannes Berg   mac80211: annotat...
702
703
  	tbl = rcu_dereference(mesh_paths);
  	for_each_mesh_entry(tbl, p, node, i) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
704
  		mpath = node->mpath;
349eb8cf4   Johannes Berg   mac80211: annotat...
705
  		if (rcu_dereference(mpath->next_hop) == sta &&
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
706
707
  		    mpath->flags & MESH_PATH_ACTIVE &&
  		    !(mpath->flags & MESH_PATH_FIXED)) {
f5e50cd07   Javier Cardona   mac80211: Improve...
708
  			spin_lock_bh(&mpath->state_lock);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
709
  			mpath->flags &= ~MESH_PATH_ACTIVE;
d19b3bf63   Rui Paulo   mac80211: replace...
710
  			++mpath->sn;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
711
  			spin_unlock_bh(&mpath->state_lock);
45904f216   Javier Cardona   nl80211/mac80211:...
712
713
  			mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
  					mpath->dst, cpu_to_le32(mpath->sn),
25d49e4d6   Thomas Pedersen   mac80211: update ...
714
  					reason, bcast, sdata);
f5e50cd07   Javier Cardona   mac80211: Improve...
715
  		}
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
716
717
718
  	}
  	rcu_read_unlock();
  }
19c50b3dc   Javier Cardona   mac80211: Don't i...
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  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...
744
745
746
747
748
  /**
   * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
   *
   * @sta - mesh peer to match
   *
b4e08ea14   Luis Carlos Cobo   mac80211: add PLI...
749
750
751
   * 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...
752
753
   * 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...
754
755
756
   */
  void mesh_path_flush_by_nexthop(struct sta_info *sta)
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
757
  	struct mesh_table *tbl;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
758
759
760
761
  	struct mesh_path *mpath;
  	struct mpath_node *node;
  	struct hlist_node *p;
  	int i;
349eb8cf4   Johannes Berg   mac80211: annotat...
762
  	rcu_read_lock();
239289e44   Javier Cardona   mac80211: Consoli...
763
764
  	read_lock_bh(&pathtbl_resize_lock);
  	tbl = resize_dereference_mesh_paths();
349eb8cf4   Johannes Berg   mac80211: annotat...
765
  	for_each_mesh_entry(tbl, p, node, i) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
766
  		mpath = node->mpath;
cd72e8174   Javier Cardona   mac80211: Consoli...
767
  		if (rcu_dereference(mpath->next_hop) == sta) {
19c50b3dc   Javier Cardona   mac80211: Don't i...
768
769
770
771
  			spin_lock_bh(&tbl->hashwlock[i]);
  			__mesh_path_del(tbl, node);
  			spin_unlock_bh(&tbl->hashwlock[i]);
  		}
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
772
  	}
239289e44   Javier Cardona   mac80211: Consoli...
773
  	read_unlock_bh(&pathtbl_resize_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
774
  	rcu_read_unlock();
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
775
  }
cd72e8174   Javier Cardona   mac80211: Consoli...
776
777
  static void table_flush_by_iface(struct mesh_table *tbl,
  				 struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
778
779
780
781
782
  {
  	struct mesh_path *mpath;
  	struct mpath_node *node;
  	struct hlist_node *p;
  	int i;
cd72e8174   Javier Cardona   mac80211: Consoli...
783
  	WARN_ON(!rcu_read_lock_held());
349eb8cf4   Johannes Berg   mac80211: annotat...
784
  	for_each_mesh_entry(tbl, p, node, i) {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
785
  		mpath = node->mpath;
cd72e8174   Javier Cardona   mac80211: Consoli...
786
787
  		if (mpath->sdata != sdata)
  			continue;
ece1a2e7e   Javier Cardona   mac80211: Remove ...
788
  		spin_lock_bh(&tbl->hashwlock[i]);
19c50b3dc   Javier Cardona   mac80211: Don't i...
789
  		__mesh_path_del(tbl, node);
ece1a2e7e   Javier Cardona   mac80211: Remove ...
790
  		spin_unlock_bh(&tbl->hashwlock[i]);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
791
792
  	}
  }
ece1a2e7e   Javier Cardona   mac80211: Remove ...
793
794
795
796
797
798
799
800
801
  /**
   * 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.
   *
   * @sdata - interface data to match
   *
   */
  void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
802
  {
cd72e8174   Javier Cardona   mac80211: Consoli...
803
  	struct mesh_table *tbl;
d0709a651   Johannes Berg   mac80211: RCU-ify...
804

cd72e8174   Javier Cardona   mac80211: Consoli...
805
  	rcu_read_lock();
239289e44   Javier Cardona   mac80211: Consoli...
806
807
  	read_lock_bh(&pathtbl_resize_lock);
  	tbl = resize_dereference_mesh_paths();
cd72e8174   Javier Cardona   mac80211: Consoli...
808
  	table_flush_by_iface(tbl, sdata);
239289e44   Javier Cardona   mac80211: Consoli...
809
  	tbl = resize_dereference_mpp_paths();
cd72e8174   Javier Cardona   mac80211: Consoli...
810
  	table_flush_by_iface(tbl, sdata);
239289e44   Javier Cardona   mac80211: Consoli...
811
  	read_unlock_bh(&pathtbl_resize_lock);
cd72e8174   Javier Cardona   mac80211: Consoli...
812
  	rcu_read_unlock();
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
813
814
815
816
817
818
  }
  
  /**
   * mesh_path_del - delete a mesh path from the table
   *
   * @addr: dst address (ETH_ALEN length)
f698d856f   Jasper Bryant-Greene   replace net_devic...
819
   * @sdata: local subif
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
820
   *
af901ca18   André Goddard Rosa   tree-wide: fix as...
821
   * Returns: 0 if successful
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
822
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
823
  int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
824
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
825
  	struct mesh_table *tbl;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
826
827
828
829
830
831
  	struct mesh_path *mpath;
  	struct mpath_node *node;
  	struct hlist_head *bucket;
  	struct hlist_node *n;
  	int hash_idx;
  	int err = 0;
9b84b8089   Javier Cardona   mac80211: Fix loc...
832
  	read_lock_bh(&pathtbl_resize_lock);
349eb8cf4   Johannes Berg   mac80211: annotat...
833
834
835
  	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...
836

349eb8cf4   Johannes Berg   mac80211: annotat...
837
  	spin_lock_bh(&tbl->hashwlock[hash_idx]);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
838
839
  	hlist_for_each_entry(node, n, bucket, list) {
  		mpath = node->mpath;
f698d856f   Jasper Bryant-Greene   replace net_devic...
840
  		if (mpath->sdata == sdata &&
349eb8cf4   Johannes Berg   mac80211: annotat...
841
  		    memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
19c50b3dc   Javier Cardona   mac80211: Don't i...
842
  			__mesh_path_del(tbl, node);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
843
844
845
846
847
848
  			goto enddel;
  		}
  	}
  
  	err = -ENXIO;
  enddel:
f5ea9120b   Johannes Berg   nl80211: add gene...
849
  	mesh_paths_generation++;
349eb8cf4   Johannes Berg   mac80211: annotat...
850
  	spin_unlock_bh(&tbl->hashwlock[hash_idx]);
9b84b8089   Javier Cardona   mac80211: Fix loc...
851
  	read_unlock_bh(&pathtbl_resize_lock);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
852
853
854
855
856
857
858
859
860
861
862
863
864
  	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...
865
866
867
  	if (mpath->flags & MESH_PATH_ACTIVE)
  		ieee80211_add_pending_skbs(mpath->sdata->local,
  				&mpath->frame_queue);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
868
869
870
  }
  
  /**
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
   * 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;
  	struct hlist_node *n;
  	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;
  
  	hlist_for_each_entry_rcu(gate, n, known_gates, list) {
  		if (gate->mpath->sdata != sdata)
  			continue;
  
  		if (gate->mpath->flags & MESH_PATH_ACTIVE) {
  			mpath_dbg("Forwarding to %pM
  ", gate->mpath->dst);
  			mesh_path_move_to_queue(gate->mpath, from_mpath, copy);
  			from_mpath = gate->mpath;
  			copy = true;
  		} else {
  			mpath_dbg("Not forwarding %p
  ", gate->mpath);
  			mpath_dbg("flags %x
  ", gate->mpath->flags);
  		}
  	}
  
  	hlist_for_each_entry_rcu(gate, n, known_gates, list)
  		if (gate->mpath->sdata == sdata) {
  			mpath_dbg("Sending to %pM
  ", gate->mpath->dst);
  			mesh_path_tx_pending(gate->mpath);
  		}
  
  	return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
  }
  
  /**
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
927
928
929
   * mesh_path_discard_frame - discard a frame whose path could not be resolved
   *
   * @skb: frame to discard
f698d856f   Jasper Bryant-Greene   replace net_devic...
930
   * @sdata: network subif the frame was to be sent through
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
931
   *
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
932
933
   * Locking: the function must me called within a rcu_read_lock region
   */
f698d856f   Jasper Bryant-Greene   replace net_devic...
934
935
  void mesh_path_discard_frame(struct sk_buff *skb,
  			     struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
936
  {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
937
  	kfree_skb(skb);
472dbc45d   Johannes Berg   mac80211: split o...
938
  	sdata->u.mesh.mshstats.dropped_frames_no_route++;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
939
940
941
942
943
944
945
  }
  
  /**
   * 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...
946
   * Locking: the function must me called within a rcu_read_lock region
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
947
948
949
   */
  void mesh_path_flush_pending(struct mesh_path *mpath)
  {
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
950
  	struct sk_buff *skb;
00e3f25c8   Javier Cardona   mac80211: fix mes...
951
  	while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
f698d856f   Jasper Bryant-Greene   replace net_devic...
952
  		mesh_path_discard_frame(skb, mpath->sdata);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  }
  
  /**
   * 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...
967
  	mpath->sn = 0xffff;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
  	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...
983
984
  	if (free_leafs) {
  		del_timer_sync(&mpath->timer);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
985
  		kfree(mpath);
d0df9eecf   Javier Cardona   mac80211: Deactiv...
986
  	}
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
987
988
  	kfree(node);
  }
4caf86c69   Pavel Emelyanov   mac80211: Prepare...
989
  static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
990
991
992
993
  {
  	struct mesh_path *mpath;
  	struct mpath_node *node, *new_node;
  	u32 hash_idx;
8566dc3fc   Pavel Emelyanov   mac80211: Fix sle...
994
  	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
00242c40a   Pavel Emelyanov   mac80211: Report ...
995
996
  	if (new_node == NULL)
  		return -ENOMEM;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
997
998
  	node = hlist_entry(p, struct mpath_node, list);
  	mpath = node->mpath;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
999
  	new_node->mpath = mpath;
f698d856f   Jasper Bryant-Greene   replace net_devic...
1000
  	hash_idx = mesh_table_hash(mpath->dst, mpath->sdata, newtbl);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1001
1002
  	hlist_add_head(&new_node->list,
  			&newtbl->hash_buckets[hash_idx]);
4caf86c69   Pavel Emelyanov   mac80211: Prepare...
1003
  	return 0;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1004
1005
1006
1007
  }
  
  int mesh_pathtbl_init(void)
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
1008
  	struct mesh_table *tbl_path, *tbl_mpp;
4c5ade414   Dan Carpenter   mac80211: handle ...
1009
  	int ret;
349eb8cf4   Johannes Berg   mac80211: annotat...
1010
1011
1012
  
  	tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
  	if (!tbl_path)
79617deee   YanBo   mac80211: mesh po...
1013
  		return -ENOMEM;
349eb8cf4   Johannes Berg   mac80211: annotat...
1014
1015
1016
  	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...
1017
  	tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
4c5ade414   Dan Carpenter   mac80211: handle ...
1018
1019
1020
1021
  	if (!tbl_path->known_gates) {
  		ret = -ENOMEM;
  		goto free_path;
  	}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1022
  	INIT_HLIST_HEAD(tbl_path->known_gates);
79617deee   YanBo   mac80211: mesh po...
1023

349eb8cf4   Johannes Berg   mac80211: annotat...
1024
1025
  	tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
  	if (!tbl_mpp) {
4c5ade414   Dan Carpenter   mac80211: handle ...
1026
1027
  		ret = -ENOMEM;
  		goto free_path;
79617deee   YanBo   mac80211: mesh po...
1028
  	}
349eb8cf4   Johannes Berg   mac80211: annotat...
1029
1030
1031
  	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...
1032
  	tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
4c5ade414   Dan Carpenter   mac80211: handle ...
1033
1034
1035
1036
  	if (!tbl_mpp->known_gates) {
  		ret = -ENOMEM;
  		goto free_mpp;
  	}
5ee68e5b3   Javier Cardona   mac80211: mesh ga...
1037
  	INIT_HLIST_HEAD(tbl_mpp->known_gates);
349eb8cf4   Johannes Berg   mac80211: annotat...
1038
1039
1040
1041
  
  	/* 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...
1042

eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1043
  	return 0;
4c5ade414   Dan Carpenter   mac80211: handle ...
1044
1045
1046
1047
1048
1049
  
  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...
1050
  }
f698d856f   Jasper Bryant-Greene   replace net_devic...
1051
  void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1052
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
1053
  	struct mesh_table *tbl;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1054
1055
1056
1057
  	struct mesh_path *mpath;
  	struct mpath_node *node;
  	struct hlist_node *p;
  	int i;
349eb8cf4   Johannes Berg   mac80211: annotat...
1058
1059
1060
  	rcu_read_lock();
  	tbl = rcu_dereference(mesh_paths);
  	for_each_mesh_entry(tbl, p, node, i) {
f698d856f   Jasper Bryant-Greene   replace net_devic...
1061
  		if (node->mpath->sdata != sdata)
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1062
1063
  			continue;
  		mpath = node->mpath;
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1064
1065
  		if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
  		    (!(mpath->flags & MESH_PATH_FIXED)) &&
f5e50cd07   Javier Cardona   mac80211: Improve...
1066
  		     time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
f698d856f   Jasper Bryant-Greene   replace net_devic...
1067
  			mesh_path_del(mpath->dst, mpath->sdata);
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1068
  	}
349eb8cf4   Johannes Berg   mac80211: annotat...
1069
  	rcu_read_unlock();
eb2b9311f   Luis Carlos Cobo   mac80211: mesh pa...
1070
1071
1072
1073
  }
  
  void mesh_pathtbl_unregister(void)
  {
349eb8cf4   Johannes Berg   mac80211: annotat...
1074
  	/* no need for locking during exit path */
33d480ce6   Eric Dumazet   net: cleanup some...
1075
1076
  	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...
1077
  }