blob: 7455397f8c3b6a74f67ce3364d29206208382b22 [file] [log] [blame]
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +01001/*
Rui Paulo264d9b72009-11-09 23:46:58 +00002 * Copyright (c) 2008, 2009 open80211s Ltd.
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +01003 * Author: Luis Carlos Cobo <luisca@cozybit.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/etherdevice.h>
11#include <linux/list.h>
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +010012#include <linux/random.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090013#include <linux/slab.h>
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +010014#include <linux/spinlock.h>
15#include <linux/string.h>
16#include <net/mac80211.h>
Javier Cardona4777be42011-09-07 17:49:52 -070017#include "wme.h"
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +010018#include "ieee80211_i.h"
19#include "mesh.h"
20
Bob Copeland60854fd2016-03-02 10:09:20 -050021static u32 mesh_table_hash(const void *addr, u32 len, u32 seed)
22{
23 /* Use last four bytes of hw addr as hash index */
24 return jhash_1word(*(u32 *)(addr+2), seed);
25}
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +010026
Bob Copeland60854fd2016-03-02 10:09:20 -050027static const struct rhashtable_params mesh_rht_params = {
28 .nelem_hint = 2,
29 .automatic_shrinking = true,
30 .key_len = ETH_ALEN,
31 .key_offset = offsetof(struct mesh_path, dst),
32 .head_offset = offsetof(struct mesh_path, rhash),
33 .hashfn = mesh_table_hash,
34};
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +010035
Johannes Bergbf7cd942013-02-15 14:40:31 +010036static inline bool mpath_expired(struct mesh_path *mpath)
37{
38 return (mpath->flags & MESH_PATH_ACTIVE) &&
39 time_after(jiffies, mpath->exp_time) &&
40 !(mpath->flags & MESH_PATH_FIXED);
41}
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +010042
Bob Copeland60854fd2016-03-02 10:09:20 -050043static void mesh_path_reclaim(struct rcu_head *rp)
Henning Rogge4cc955d2016-02-03 13:58:38 +010044{
Bob Copeland60854fd2016-03-02 10:09:20 -050045 struct mesh_path *mpath = container_of(rp, struct mesh_path, rcu);
46
47 del_timer_sync(&mpath->timer);
48 kfree(mpath);
Henning Rogge4cc955d2016-02-03 13:58:38 +010049}
50
Bob Copeland60854fd2016-03-02 10:09:20 -050051static void mesh_path_rht_free(void *ptr, void *unused_arg)
Johannes Berg349eb8c2011-05-14 11:56:16 +020052{
Bob Copeland60854fd2016-03-02 10:09:20 -050053 struct mesh_path *mpath = ptr;
54 call_rcu(&mpath->rcu, mesh_path_reclaim);
Johannes Berg349eb8c2011-05-14 11:56:16 +020055}
56
Bob Copeland60854fd2016-03-02 10:09:20 -050057static struct mesh_table *mesh_table_alloc(void)
Johannes Berg349eb8c2011-05-14 11:56:16 +020058{
Johannes Berg6b86bd62011-05-12 13:38:50 +020059 struct mesh_table *newtbl;
60
Javier Cardonad676ff42011-05-17 16:13:34 -070061 newtbl = kmalloc(sizeof(struct mesh_table), GFP_ATOMIC);
Johannes Berg6b86bd62011-05-12 13:38:50 +020062 if (!newtbl)
63 return NULL;
64
Bob Copeland60854fd2016-03-02 10:09:20 -050065 newtbl->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
66 if (!newtbl->known_gates) {
Johannes Berg6b86bd62011-05-12 13:38:50 +020067 kfree(newtbl);
68 return NULL;
69 }
Bob Copeland60854fd2016-03-02 10:09:20 -050070 INIT_HLIST_HEAD(newtbl->known_gates);
Johannes Berg6b86bd62011-05-12 13:38:50 +020071 atomic_set(&newtbl->entries, 0);
Javier Cardona5ee68e52011-08-09 16:45:08 -070072 spin_lock_init(&newtbl->gates_lock);
Johannes Berg6b86bd62011-05-12 13:38:50 +020073
74 return newtbl;
75}
76
Bob Copeland60854fd2016-03-02 10:09:20 -050077static void mesh_table_free(struct mesh_table *tbl)
Javier Cardona18889232009-08-10 12:15:52 -070078{
Bob Copeland60854fd2016-03-02 10:09:20 -050079 rhashtable_free_and_destroy(&tbl->rhead,
80 mesh_path_rht_free, NULL);
Javier Cardona18889232009-08-10 12:15:52 -070081 kfree(tbl);
82}
83
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +010084/**
85 *
86 * mesh_path_assign_nexthop - update mesh path next hop
87 *
88 * @mpath: mesh path to update
89 * @sta: next hop to assign
90 *
91 * Locking: mpath->state_lock must be held when calling this function
92 */
93void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
94{
Javier Cardona10c836d2009-07-09 14:42:16 -070095 struct sk_buff *skb;
96 struct ieee80211_hdr *hdr;
Javier Cardona10c836d2009-07-09 14:42:16 -070097 unsigned long flags;
98
Johannes Bergd0709a62008-02-25 16:27:46 +010099 rcu_assign_pointer(mpath->next_hop, sta);
Javier Cardona10c836d2009-07-09 14:42:16 -0700100
Javier Cardona10c836d2009-07-09 14:42:16 -0700101 spin_lock_irqsave(&mpath->frame_queue.lock, flags);
Thomas Pedersenb22bd522012-08-09 18:15:39 -0700102 skb_queue_walk(&mpath->frame_queue, skb) {
Javier Cardona10c836d2009-07-09 14:42:16 -0700103 hdr = (struct ieee80211_hdr *) skb->data;
104 memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
Thomas Pedersen7e3c8862011-11-24 17:15:21 -0800105 memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN);
Marco Porsch3f52b7e2013-01-30 18:14:08 +0100106 ieee80211_mps_set_frame_flags(sta->sdata, sta, hdr);
Javier Cardona10c836d2009-07-09 14:42:16 -0700107 }
108
Javier Cardona10c836d2009-07-09 14:42:16 -0700109 spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100110}
111
Javier Cardona5ee68e52011-08-09 16:45:08 -0700112static void prepare_for_gate(struct sk_buff *skb, char *dst_addr,
113 struct mesh_path *gate_mpath)
114{
115 struct ieee80211_hdr *hdr;
116 struct ieee80211s_hdr *mshdr;
117 int mesh_hdrlen, hdrlen;
118 char *next_hop;
119
120 hdr = (struct ieee80211_hdr *) skb->data;
121 hdrlen = ieee80211_hdrlen(hdr->frame_control);
122 mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
123
124 if (!(mshdr->flags & MESH_FLAGS_AE)) {
125 /* size of the fixed part of the mesh header */
126 mesh_hdrlen = 6;
127
128 /* make room for the two extended addresses */
129 skb_push(skb, 2 * ETH_ALEN);
130 memmove(skb->data, hdr, hdrlen + mesh_hdrlen);
131
132 hdr = (struct ieee80211_hdr *) skb->data;
133
134 /* we preserve the previous mesh header and only add
135 * the new addreses */
136 mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
137 mshdr->flags = MESH_FLAGS_AE_A5_A6;
138 memcpy(mshdr->eaddr1, hdr->addr3, ETH_ALEN);
139 memcpy(mshdr->eaddr2, hdr->addr4, ETH_ALEN);
140 }
141
142 /* update next hop */
143 hdr = (struct ieee80211_hdr *) skb->data;
144 rcu_read_lock();
145 next_hop = rcu_dereference(gate_mpath->next_hop)->sta.addr;
146 memcpy(hdr->addr1, next_hop, ETH_ALEN);
147 rcu_read_unlock();
Thomas Pedersen7e3c8862011-11-24 17:15:21 -0800148 memcpy(hdr->addr2, gate_mpath->sdata->vif.addr, ETH_ALEN);
Javier Cardona5ee68e52011-08-09 16:45:08 -0700149 memcpy(hdr->addr3, dst_addr, ETH_ALEN);
150}
151
152/**
153 *
154 * mesh_path_move_to_queue - Move or copy frames from one mpath queue to another
155 *
156 * This function is used to transfer or copy frames from an unresolved mpath to
157 * a gate mpath. The function also adds the Address Extension field and
158 * updates the next hop.
159 *
160 * If a frame already has an Address Extension field, only the next hop and
161 * destination addresses are updated.
162 *
163 * The gate mpath must be an active mpath with a valid mpath->next_hop.
164 *
165 * @mpath: An active mpath the frames will be sent to (i.e. the gate)
166 * @from_mpath: The failed mpath
167 * @copy: When true, copy all the frames to the new mpath queue. When false,
168 * move them.
169 */
170static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,
171 struct mesh_path *from_mpath,
172 bool copy)
173{
Thomas Pedersen4bd4c2d2012-08-09 18:15:40 -0700174 struct sk_buff *skb, *fskb, *tmp;
175 struct sk_buff_head failq;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700176 unsigned long flags;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700177
Johannes Berg8c5bb1f2014-04-29 17:55:26 +0200178 if (WARN_ON(gate_mpath == from_mpath))
179 return;
180 if (WARN_ON(!gate_mpath->next_hop))
181 return;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700182
Javier Cardona5ee68e52011-08-09 16:45:08 -0700183 __skb_queue_head_init(&failq);
184
185 spin_lock_irqsave(&from_mpath->frame_queue.lock, flags);
186 skb_queue_splice_init(&from_mpath->frame_queue, &failq);
187 spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
188
Thomas Pedersen4bd4c2d2012-08-09 18:15:40 -0700189 skb_queue_walk_safe(&failq, fskb, tmp) {
190 if (skb_queue_len(&gate_mpath->frame_queue) >=
191 MESH_FRAME_QUEUE_LEN) {
192 mpath_dbg(gate_mpath->sdata, "mpath queue full!\n");
193 break;
John W. Linville817a53d2011-08-24 15:12:41 -0400194 }
Javier Cardona5ee68e52011-08-09 16:45:08 -0700195
Thomas Pedersen4bd4c2d2012-08-09 18:15:40 -0700196 skb = skb_copy(fskb, GFP_ATOMIC);
197 if (WARN_ON(!skb))
198 break;
199
Javier Cardona5ee68e52011-08-09 16:45:08 -0700200 prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
Thomas Pedersen4bd4c2d2012-08-09 18:15:40 -0700201 skb_queue_tail(&gate_mpath->frame_queue, skb);
202
203 if (copy)
204 continue;
205
206 __skb_unlink(fskb, &failq);
207 kfree_skb(fskb);
Javier Cardona5ee68e52011-08-09 16:45:08 -0700208 }
209
Johannes Bergbdcbd8e2012-06-22 11:29:50 +0200210 mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n",
211 gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue));
Javier Cardona5ee68e52011-08-09 16:45:08 -0700212
213 if (!copy)
214 return;
215
216 spin_lock_irqsave(&from_mpath->frame_queue.lock, flags);
217 skb_queue_splice(&failq, &from_mpath->frame_queue);
218 spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
219}
220
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100221
Johannes Berg4a3cb702013-02-12 16:43:19 +0100222static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
223 struct ieee80211_sub_if_data *sdata)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100224{
225 struct mesh_path *mpath;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100226
Bob Copeland60854fd2016-03-02 10:09:20 -0500227 mpath = rhashtable_lookup_fast(&tbl->rhead, dst, mesh_rht_params);
228
229 if (mpath && mpath_expired(mpath)) {
230 spin_lock_bh(&mpath->state_lock);
231 mpath->flags &= ~MESH_PATH_ACTIVE;
232 spin_unlock_bh(&mpath->state_lock);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100233 }
Bob Copeland60854fd2016-03-02 10:09:20 -0500234 return mpath;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100235}
236
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100237/**
238 * mesh_path_lookup - look up a path in the mesh path table
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100239 * @sdata: local subif
Johannes Bergbf7cd942013-02-15 14:40:31 +0100240 * @dst: hardware address (ETH_ALEN length) of destination
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100241 *
242 * Returns: pointer to the mesh path structure, or NULL if not found
243 *
244 * Locking: must be called within a read rcu section.
245 */
Johannes Bergbf7cd942013-02-15 14:40:31 +0100246struct mesh_path *
247mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100248{
Bob Copeland60854fd2016-03-02 10:09:20 -0500249 return mpath_lookup(sdata->u.mesh.mesh_paths, dst, sdata);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100250}
251
Johannes Bergbf7cd942013-02-15 14:40:31 +0100252struct mesh_path *
253mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
YanBo79617de2008-09-22 13:30:32 +0800254{
Bob Copeland60854fd2016-03-02 10:09:20 -0500255 return mpath_lookup(sdata->u.mesh.mpp_paths, dst, sdata);
YanBo79617de2008-09-22 13:30:32 +0800256}
257
Bob Copeland60854fd2016-03-02 10:09:20 -0500258static struct mesh_path *
259__mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx)
260{
261 int i = 0, ret;
262 struct mesh_path *mpath = NULL;
263 struct rhashtable_iter iter;
264
265 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
266 if (ret)
267 return NULL;
268
269 ret = rhashtable_walk_start(&iter);
270 if (ret && ret != -EAGAIN)
271 goto err;
272
273 while ((mpath = rhashtable_walk_next(&iter))) {
274 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
275 continue;
276 if (IS_ERR(mpath))
277 break;
278 if (i++ == idx)
279 break;
280 }
281err:
282 rhashtable_walk_stop(&iter);
283 rhashtable_walk_exit(&iter);
284
285 if (IS_ERR(mpath) || !mpath)
286 return NULL;
287
288 if (mpath_expired(mpath)) {
289 spin_lock_bh(&mpath->state_lock);
290 mpath->flags &= ~MESH_PATH_ACTIVE;
291 spin_unlock_bh(&mpath->state_lock);
292 }
293 return mpath;
294}
YanBo79617de2008-09-22 13:30:32 +0800295
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100296/**
297 * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
298 * @idx: index
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +1200299 * @sdata: local subif, or NULL for all entries
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100300 *
301 * Returns: pointer to the mesh path structure, or NULL if not found.
302 *
303 * Locking: must be called within a read rcu section.
304 */
Johannes Bergbf7cd942013-02-15 14:40:31 +0100305struct mesh_path *
306mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100307{
Bob Copeland60854fd2016-03-02 10:09:20 -0500308 return __mesh_path_lookup_by_idx(sdata->u.mesh.mesh_paths, idx);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100309}
310
Javier Cardona5ee68e52011-08-09 16:45:08 -0700311/**
Henning Roggea2db2ed2014-09-12 08:58:50 +0200312 * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
313 * @idx: index
314 * @sdata: local subif, or NULL for all entries
315 *
316 * Returns: pointer to the proxy path structure, or NULL if not found.
317 *
318 * Locking: must be called within a read rcu section.
319 */
320struct mesh_path *
321mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
322{
Bob Copeland60854fd2016-03-02 10:09:20 -0500323 return __mesh_path_lookup_by_idx(sdata->u.mesh.mpp_paths, idx);
Henning Roggea2db2ed2014-09-12 08:58:50 +0200324}
325
326/**
Johannes Berg30be52e2011-11-21 11:23:50 +0100327 * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
328 * @mpath: gate path to add to table
Javier Cardona5ee68e52011-08-09 16:45:08 -0700329 */
Johannes Berg30be52e2011-11-21 11:23:50 +0100330int mesh_path_add_gate(struct mesh_path *mpath)
Javier Cardona5ee68e52011-08-09 16:45:08 -0700331{
Johannes Berg30be52e2011-11-21 11:23:50 +0100332 struct mesh_table *tbl;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700333 int err;
334
335 rcu_read_lock();
Bob Copeland60854fd2016-03-02 10:09:20 -0500336 tbl = mpath->sdata->u.mesh.mesh_paths;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700337
Bob Copeland947c2a02016-02-28 20:03:59 -0500338 spin_lock_bh(&mpath->state_lock);
339 if (mpath->is_gate) {
340 err = -EEXIST;
341 spin_unlock_bh(&mpath->state_lock);
Javier Cardona5ee68e52011-08-09 16:45:08 -0700342 goto err_rcu;
343 }
Javier Cardona5ee68e52011-08-09 16:45:08 -0700344 mpath->is_gate = true;
345 mpath->sdata->u.mesh.num_gates++;
Bob Copeland947c2a02016-02-28 20:03:59 -0500346
347 spin_lock(&tbl->gates_lock);
348 hlist_add_head_rcu(&mpath->gate_list, tbl->known_gates);
349 spin_unlock(&tbl->gates_lock);
350
351 spin_unlock_bh(&mpath->state_lock);
352
Johannes Bergbdcbd8e2012-06-22 11:29:50 +0200353 mpath_dbg(mpath->sdata,
354 "Mesh path: Recorded new gate: %pM. %d known gates\n",
355 mpath->dst, mpath->sdata->u.mesh.num_gates);
Johannes Bergbf7cd942013-02-15 14:40:31 +0100356 err = 0;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700357err_rcu:
358 rcu_read_unlock();
359 return err;
360}
361
362/**
363 * mesh_gate_del - remove a mesh gate from the list of known gates
364 * @tbl: table which holds our list of known gates
365 * @mpath: gate mpath
Javier Cardona5ee68e52011-08-09 16:45:08 -0700366 */
Johannes Bergbf7cd942013-02-15 14:40:31 +0100367static void mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
Javier Cardona5ee68e52011-08-09 16:45:08 -0700368{
Bob Copeland947c2a02016-02-28 20:03:59 -0500369 lockdep_assert_held(&mpath->state_lock);
370 if (!mpath->is_gate)
371 return;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700372
Bob Copeland947c2a02016-02-28 20:03:59 -0500373 mpath->is_gate = false;
374 spin_lock_bh(&tbl->gates_lock);
375 hlist_del_rcu(&mpath->gate_list);
376 mpath->sdata->u.mesh.num_gates--;
377 spin_unlock_bh(&tbl->gates_lock);
378
379 mpath_dbg(mpath->sdata,
380 "Mesh path: Deleted gate: %pM. %d known gates\n",
381 mpath->dst, mpath->sdata->u.mesh.num_gates);
Javier Cardona5ee68e52011-08-09 16:45:08 -0700382}
383
384/**
Javier Cardona5ee68e52011-08-09 16:45:08 -0700385 * mesh_gate_num - number of gates known to this interface
386 * @sdata: subif data
387 */
388int mesh_gate_num(struct ieee80211_sub_if_data *sdata)
389{
390 return sdata->u.mesh.num_gates;
391}
392
Bob Copelandb15dc382016-02-28 20:03:58 -0500393static
394struct mesh_path *mesh_path_new(struct ieee80211_sub_if_data *sdata,
395 const u8 *dst, gfp_t gfp_flags)
396{
397 struct mesh_path *new_mpath;
398
399 new_mpath = kzalloc(sizeof(struct mesh_path), gfp_flags);
400 if (!new_mpath)
401 return NULL;
402
403 memcpy(new_mpath->dst, dst, ETH_ALEN);
404 eth_broadcast_addr(new_mpath->rann_snd_addr);
405 new_mpath->is_root = false;
406 new_mpath->sdata = sdata;
407 new_mpath->flags = 0;
408 skb_queue_head_init(&new_mpath->frame_queue);
409 new_mpath->timer.data = (unsigned long) new_mpath;
410 new_mpath->timer.function = mesh_path_timer;
411 new_mpath->exp_time = jiffies;
412 spin_lock_init(&new_mpath->state_lock);
413 init_timer(&new_mpath->timer);
414
415 return new_mpath;
416}
417
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100418/**
419 * mesh_path_add - allocate and add a new path to the mesh path table
Johannes Bergbf7cd942013-02-15 14:40:31 +0100420 * @dst: destination address of the path (ETH_ALEN length)
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +1200421 * @sdata: local subif
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100422 *
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200423 * Returns: 0 on success
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100424 *
425 * State: the initial state of the new path is set to 0
426 */
Bob Copelandae76eef2013-03-29 09:38:39 -0400427struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
428 const u8 *dst)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100429{
Johannes Berg349eb8c2011-05-14 11:56:16 +0200430 struct mesh_table *tbl;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100431 struct mesh_path *mpath, *new_mpath;
Bob Copeland60854fd2016-03-02 10:09:20 -0500432 int ret;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100433
Joe Perchesb203ca32012-05-08 18:56:52 +0000434 if (ether_addr_equal(dst, sdata->vif.addr))
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100435 /* never add ourselves as neighbours */
Bob Copelandae76eef2013-03-29 09:38:39 -0400436 return ERR_PTR(-ENOTSUPP);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100437
438 if (is_multicast_ether_addr(dst))
Bob Copelandae76eef2013-03-29 09:38:39 -0400439 return ERR_PTR(-ENOTSUPP);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100440
Johannes Berg472dbc42008-09-11 00:01:49 +0200441 if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0)
Bob Copelandae76eef2013-03-29 09:38:39 -0400442 return ERR_PTR(-ENOSPC);
443
Bob Copelandb15dc382016-02-28 20:03:58 -0500444 new_mpath = mesh_path_new(sdata, dst, GFP_ATOMIC);
Pavel Emelyanov402d7752008-05-06 18:53:43 +0400445 if (!new_mpath)
Bob Copeland60854fd2016-03-02 10:09:20 -0500446 return ERR_PTR(-ENOMEM);
Pavel Emelyanov402d7752008-05-06 18:53:43 +0400447
Bob Copeland60854fd2016-03-02 10:09:20 -0500448 tbl = sdata->u.mesh.mesh_paths;
449 do {
450 ret = rhashtable_lookup_insert_fast(&tbl->rhead,
451 &new_mpath->rhash,
452 mesh_rht_params);
Pavel Emelyanovf84e71a2008-05-06 18:46:36 +0400453
Bob Copeland60854fd2016-03-02 10:09:20 -0500454 if (ret == -EEXIST)
455 mpath = rhashtable_lookup_fast(&tbl->rhead,
456 dst,
457 mesh_rht_params);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100458
Bob Copeland60854fd2016-03-02 10:09:20 -0500459 } while (unlikely(ret == -EEXIST && !mpath));
460
461 if (ret && ret != -EEXIST)
462 return ERR_PTR(ret);
463
464 /* At this point either new_mpath was added, or we found a
465 * matching entry already in the table; in the latter case
466 * free the unnecessary new entry.
467 */
468 if (ret == -EEXIST) {
469 kfree(new_mpath);
470 new_mpath = mpath;
471 }
Bob Copeland2bdaf382016-02-28 20:03:56 -0500472 sdata->u.mesh.mesh_paths_generation++;
Bob Copeland60854fd2016-03-02 10:09:20 -0500473 return new_mpath;
Javier Cardona18889232009-08-10 12:15:52 -0700474}
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100475
Johannes Bergbf7cd942013-02-15 14:40:31 +0100476int mpp_path_add(struct ieee80211_sub_if_data *sdata,
477 const u8 *dst, const u8 *mpp)
YanBo79617de2008-09-22 13:30:32 +0800478{
Johannes Berg349eb8c2011-05-14 11:56:16 +0200479 struct mesh_table *tbl;
Bob Copeland60854fd2016-03-02 10:09:20 -0500480 struct mesh_path *new_mpath;
481 int ret;
YanBo79617de2008-09-22 13:30:32 +0800482
Joe Perchesb203ca32012-05-08 18:56:52 +0000483 if (ether_addr_equal(dst, sdata->vif.addr))
YanBo79617de2008-09-22 13:30:32 +0800484 /* never add ourselves as neighbours */
485 return -ENOTSUPP;
486
487 if (is_multicast_ether_addr(dst))
488 return -ENOTSUPP;
489
Bob Copelandb15dc382016-02-28 20:03:58 -0500490 new_mpath = mesh_path_new(sdata, dst, GFP_ATOMIC);
YanBo79617de2008-09-22 13:30:32 +0800491
Bob Copeland60854fd2016-03-02 10:09:20 -0500492 if (!new_mpath)
493 return -ENOMEM;
YanBo79617de2008-09-22 13:30:32 +0800494
YanBo79617de2008-09-22 13:30:32 +0800495 memcpy(new_mpath->mpp, mpp, ETH_ALEN);
Bob Copeland60854fd2016-03-02 10:09:20 -0500496 tbl = sdata->u.mesh.mpp_paths;
497 ret = rhashtable_lookup_insert_fast(&tbl->rhead,
498 &new_mpath->rhash,
499 mesh_rht_params);
Henning Roggea2db2ed2014-09-12 08:58:50 +0200500
Bob Copeland2bdaf382016-02-28 20:03:56 -0500501 sdata->u.mesh.mpp_paths_generation++;
Bob Copeland60854fd2016-03-02 10:09:20 -0500502 return ret;
YanBo79617de2008-09-22 13:30:32 +0800503}
504
505
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100506/**
507 * mesh_plink_broken - deactivates paths and sends perr when a link breaks
508 *
509 * @sta: broken peer link
510 *
511 * This function must be called from the rate control algorithm if enough
512 * delivery errors suggest that a peer link is no longer usable.
513 */
514void mesh_plink_broken(struct sta_info *sta)
515{
Bob Copeland60854fd2016-03-02 10:09:20 -0500516 struct ieee80211_sub_if_data *sdata = sta->sdata;
517 struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
Johannes Berg15ff6362009-11-17 13:34:04 +0100518 static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100519 struct mesh_path *mpath;
Bob Copeland60854fd2016-03-02 10:09:20 -0500520 struct rhashtable_iter iter;
521 int ret;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100522
Bob Copeland60854fd2016-03-02 10:09:20 -0500523 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
524 if (ret)
525 return;
526
527 ret = rhashtable_walk_start(&iter);
528 if (ret && ret != -EAGAIN)
529 goto out;
530
531 while ((mpath = rhashtable_walk_next(&iter))) {
532 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
533 continue;
534 if (IS_ERR(mpath))
535 break;
Andreea-Cristina Bernat2688eba2014-08-17 16:18:02 +0300536 if (rcu_access_pointer(mpath->next_hop) == sta &&
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100537 mpath->flags & MESH_PATH_ACTIVE &&
538 !(mpath->flags & MESH_PATH_FIXED)) {
Javier Cardonaf5e50cd2011-08-29 13:23:05 -0700539 spin_lock_bh(&mpath->state_lock);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100540 mpath->flags &= ~MESH_PATH_ACTIVE;
Rui Paulod19b3bf2009-11-09 23:46:55 +0000541 ++mpath->sn;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100542 spin_unlock_bh(&mpath->state_lock);
Johannes Bergbf7cd942013-02-15 14:40:31 +0100543 mesh_path_error_tx(sdata,
Chun-Yeow Yeohf63f8422013-11-13 15:39:12 +0800544 sdata->u.mesh.mshcfg.element_ttl,
545 mpath->dst, mpath->sn,
546 WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
Javier Cardonaf5e50cd2011-08-29 13:23:05 -0700547 }
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100548 }
Bob Copeland60854fd2016-03-02 10:09:20 -0500549out:
550 rhashtable_walk_stop(&iter);
551 rhashtable_walk_exit(&iter);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100552}
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100553
Bob Copeland60854fd2016-03-02 10:09:20 -0500554static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath)
Javier Cardona19c50b32011-08-29 13:23:07 -0700555{
Bob Copeland60854fd2016-03-02 10:09:20 -0500556 struct ieee80211_sub_if_data *sdata = mpath->sdata;
Javier Cardona19c50b32011-08-29 13:23:07 -0700557
Bob Copeland60854fd2016-03-02 10:09:20 -0500558 rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params);
Bob Copeland947c2a02016-02-28 20:03:59 -0500559 spin_lock_bh(&mpath->state_lock);
Javier Cardona19c50b32011-08-29 13:23:07 -0700560 mpath->flags |= MESH_PATH_RESOLVING;
Bob Copeland60854fd2016-03-02 10:09:20 -0500561 mesh_gate_del(tbl, mpath);
562 call_rcu(&mpath->rcu, mesh_path_reclaim);
Bob Copeland947c2a02016-02-28 20:03:59 -0500563 spin_unlock_bh(&mpath->state_lock);
Johannes Bergc2e703a2015-11-17 14:25:21 +0100564 atomic_dec(&sdata->u.mesh.mpaths);
Javier Cardona19c50b32011-08-29 13:23:07 -0700565 atomic_dec(&tbl->entries);
566}
567
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100568/**
569 * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
570 *
Ben Hutchings2c530402012-07-10 10:55:09 +0000571 * @sta: mesh peer to match
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100572 *
Luis Carlos Cobob4e08ea2008-02-29 15:46:08 -0800573 * RCU notes: this function is called when a mesh plink transitions from
574 * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that
575 * allows path creation. This will happen before the sta can be freed (because
Johannes Bergd0709a62008-02-25 16:27:46 +0100576 * sta_info_destroy() calls this) so any reader in a rcu read block will be
577 * protected against the plink disappearing.
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100578 */
579void mesh_path_flush_by_nexthop(struct sta_info *sta)
580{
Bob Copeland2bdaf382016-02-28 20:03:56 -0500581 struct ieee80211_sub_if_data *sdata = sta->sdata;
Bob Copeland60854fd2016-03-02 10:09:20 -0500582 struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100583 struct mesh_path *mpath;
Bob Copeland60854fd2016-03-02 10:09:20 -0500584 struct rhashtable_iter iter;
585 int ret;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100586
Bob Copeland60854fd2016-03-02 10:09:20 -0500587 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
588 if (ret)
589 return;
590
591 ret = rhashtable_walk_start(&iter);
592 if (ret && ret != -EAGAIN)
593 goto out;
594
595 while ((mpath = rhashtable_walk_next(&iter))) {
596 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
597 continue;
598 if (IS_ERR(mpath))
599 break;
600
601 if (rcu_access_pointer(mpath->next_hop) == sta)
602 __mesh_path_del(tbl, mpath);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100603 }
Bob Copeland60854fd2016-03-02 10:09:20 -0500604out:
605 rhashtable_walk_stop(&iter);
606 rhashtable_walk_exit(&iter);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100607}
608
Henning Roggebf5a70e2016-02-03 13:58:36 +0100609static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
610 const u8 *proxy)
611{
Bob Copeland60854fd2016-03-02 10:09:20 -0500612 struct mesh_table *tbl = sdata->u.mesh.mpp_paths;
613 struct mesh_path *mpath;
614 struct rhashtable_iter iter;
615 int ret;
Henning Roggebf5a70e2016-02-03 13:58:36 +0100616
Bob Copeland60854fd2016-03-02 10:09:20 -0500617 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
618 if (ret)
619 return;
620
621 ret = rhashtable_walk_start(&iter);
622 if (ret && ret != -EAGAIN)
623 goto out;
624
625 while ((mpath = rhashtable_walk_next(&iter))) {
626 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
627 continue;
628 if (IS_ERR(mpath))
629 break;
630
631 if (ether_addr_equal(mpath->mpp, proxy))
632 __mesh_path_del(tbl, mpath);
Henning Roggebf5a70e2016-02-03 13:58:36 +0100633 }
Bob Copeland60854fd2016-03-02 10:09:20 -0500634out:
635 rhashtable_walk_stop(&iter);
636 rhashtable_walk_exit(&iter);
Henning Roggebf5a70e2016-02-03 13:58:36 +0100637}
638
Bob Copeland60854fd2016-03-02 10:09:20 -0500639static void table_flush_by_iface(struct mesh_table *tbl)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100640{
641 struct mesh_path *mpath;
Bob Copeland60854fd2016-03-02 10:09:20 -0500642 struct rhashtable_iter iter;
643 int ret;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100644
Bob Copeland60854fd2016-03-02 10:09:20 -0500645 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
646 if (ret)
647 return;
648
649 ret = rhashtable_walk_start(&iter);
650 if (ret && ret != -EAGAIN)
651 goto out;
652
653 while ((mpath = rhashtable_walk_next(&iter))) {
654 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
655 continue;
656 if (IS_ERR(mpath))
657 break;
658 __mesh_path_del(tbl, mpath);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100659 }
Bob Copeland60854fd2016-03-02 10:09:20 -0500660out:
661 rhashtable_walk_stop(&iter);
662 rhashtable_walk_exit(&iter);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100663}
664
Javier Cardonaece1a2e2011-08-29 13:23:04 -0700665/**
666 * mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface
667 *
668 * This function deletes both mesh paths as well as mesh portal paths.
669 *
Ben Hutchings2c530402012-07-10 10:55:09 +0000670 * @sdata: interface data to match
Javier Cardonaece1a2e2011-08-29 13:23:04 -0700671 *
672 */
673void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100674{
Bob Copeland60854fd2016-03-02 10:09:20 -0500675 table_flush_by_iface(sdata->u.mesh.mesh_paths);
676 table_flush_by_iface(sdata->u.mesh.mpp_paths);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100677}
678
679/**
Henning Rogge4cc955d2016-02-03 13:58:38 +0100680 * table_path_del - delete a path from the mesh or mpp table
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100681 *
Henning Rogge4cc955d2016-02-03 13:58:38 +0100682 * @tbl: mesh or mpp path table
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +1200683 * @sdata: local subif
Henning Rogge4cc955d2016-02-03 13:58:38 +0100684 * @addr: dst address (ETH_ALEN length)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100685 *
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200686 * Returns: 0 if successful
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100687 */
Bob Copeland60854fd2016-03-02 10:09:20 -0500688static int table_path_del(struct mesh_table *tbl,
Henning Rogge4cc955d2016-02-03 13:58:38 +0100689 struct ieee80211_sub_if_data *sdata,
690 const u8 *addr)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100691{
692 struct mesh_path *mpath;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100693
Bob Copeland60854fd2016-03-02 10:09:20 -0500694 rcu_read_lock();
695 mpath = rhashtable_lookup_fast(&tbl->rhead, addr, mesh_rht_params);
696 if (!mpath) {
697 rcu_read_unlock();
698 return -ENXIO;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100699 }
700
Bob Copeland60854fd2016-03-02 10:09:20 -0500701 __mesh_path_del(tbl, mpath);
702 rcu_read_unlock();
703 return 0;
Henning Rogge4cc955d2016-02-03 13:58:38 +0100704}
705
Bob Copeland60854fd2016-03-02 10:09:20 -0500706
Henning Rogge4cc955d2016-02-03 13:58:38 +0100707/**
708 * mesh_path_del - delete a mesh path from the table
709 *
710 * @addr: dst address (ETH_ALEN length)
711 * @sdata: local subif
712 *
713 * Returns: 0 if successful
714 */
715int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
716{
Bob Copeland60854fd2016-03-02 10:09:20 -0500717 int err;
Henning Rogge4cc955d2016-02-03 13:58:38 +0100718
719 /* flush relevant mpp entries first */
720 mpp_flush_by_proxy(sdata, addr);
721
Bob Copeland2bdaf382016-02-28 20:03:56 -0500722 err = table_path_del(sdata->u.mesh.mesh_paths, sdata, addr);
723 sdata->u.mesh.mesh_paths_generation++;
Henning Roggeab1c7902016-02-03 13:58:37 +0100724 return err;
725}
726
727/**
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100728 * mesh_path_tx_pending - sends pending frames in a mesh path queue
729 *
730 * @mpath: mesh path to activate
731 *
732 * Locking: the state_lock of the mpath structure must NOT be held when calling
733 * this function.
734 */
735void mesh_path_tx_pending(struct mesh_path *mpath)
736{
Javier Cardona249b4052009-07-07 10:55:03 -0700737 if (mpath->flags & MESH_PATH_ACTIVE)
738 ieee80211_add_pending_skbs(mpath->sdata->local,
739 &mpath->frame_queue);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100740}
741
742/**
Javier Cardona5ee68e52011-08-09 16:45:08 -0700743 * mesh_path_send_to_gates - sends pending frames to all known mesh gates
744 *
745 * @mpath: mesh path whose queue will be emptied
746 *
747 * If there is only one gate, the frames are transferred from the failed mpath
748 * queue to that gate's queue. If there are more than one gates, the frames
749 * are copied from each gate to the next. After frames are copied, the
750 * mpath queues are emptied onto the transmission queue.
751 */
752int mesh_path_send_to_gates(struct mesh_path *mpath)
753{
754 struct ieee80211_sub_if_data *sdata = mpath->sdata;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700755 struct mesh_table *tbl;
756 struct mesh_path *from_mpath = mpath;
Bob Copeland60854fd2016-03-02 10:09:20 -0500757 struct mesh_path *gate;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700758 bool copy = false;
759 struct hlist_head *known_gates;
760
Bob Copeland60854fd2016-03-02 10:09:20 -0500761 tbl = sdata->u.mesh.mesh_paths;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700762 known_gates = tbl->known_gates;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700763
764 if (!known_gates)
765 return -EHOSTUNREACH;
766
Bob Copeland60854fd2016-03-02 10:09:20 -0500767 rcu_read_lock();
Bob Copeland947c2a02016-02-28 20:03:59 -0500768 hlist_for_each_entry_rcu(gate, known_gates, gate_list) {
769 if (gate->flags & MESH_PATH_ACTIVE) {
770 mpath_dbg(sdata, "Forwarding to %pM\n", gate->dst);
771 mesh_path_move_to_queue(gate, from_mpath, copy);
772 from_mpath = gate;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700773 copy = true;
774 } else {
Johannes Bergbdcbd8e2012-06-22 11:29:50 +0200775 mpath_dbg(sdata,
Johannes Bergd671b2a2015-11-06 11:30:46 +0100776 "Not forwarding to %pM (flags %#x)\n",
Bob Copeland947c2a02016-02-28 20:03:59 -0500777 gate->dst, gate->flags);
Javier Cardona5ee68e52011-08-09 16:45:08 -0700778 }
779 }
780
Bob Copeland947c2a02016-02-28 20:03:59 -0500781 hlist_for_each_entry_rcu(gate, known_gates, gate_list) {
782 mpath_dbg(sdata, "Sending to %pM\n", gate->dst);
783 mesh_path_tx_pending(gate);
Bob Copeland2bdaf382016-02-28 20:03:56 -0500784 }
Bob Copeland60854fd2016-03-02 10:09:20 -0500785 rcu_read_unlock();
Javier Cardona5ee68e52011-08-09 16:45:08 -0700786
787 return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
788}
789
790/**
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100791 * mesh_path_discard_frame - discard a frame whose path could not be resolved
792 *
793 * @skb: frame to discard
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +1200794 * @sdata: network subif the frame was to be sent through
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100795 *
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100796 * Locking: the function must me called within a rcu_read_lock region
797 */
Johannes Bergbf7cd942013-02-15 14:40:31 +0100798void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
799 struct sk_buff *skb)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100800{
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100801 kfree_skb(skb);
Johannes Berg472dbc42008-09-11 00:01:49 +0200802 sdata->u.mesh.mshstats.dropped_frames_no_route++;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100803}
804
805/**
806 * mesh_path_flush_pending - free the pending queue of a mesh path
807 *
808 * @mpath: mesh path whose queue has to be freed
809 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300810 * Locking: the function must me called within a rcu_read_lock region
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100811 */
812void mesh_path_flush_pending(struct mesh_path *mpath)
813{
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100814 struct sk_buff *skb;
815
Javier Cardona00e3f252011-08-09 16:45:07 -0700816 while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
Johannes Bergbf7cd942013-02-15 14:40:31 +0100817 mesh_path_discard_frame(mpath->sdata, skb);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100818}
819
820/**
821 * mesh_path_fix_nexthop - force a specific next hop for a mesh path
822 *
823 * @mpath: the mesh path to modify
824 * @next_hop: the next hop to force
825 *
826 * Locking: this function must be called holding mpath->state_lock
827 */
828void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop)
829{
830 spin_lock_bh(&mpath->state_lock);
831 mesh_path_assign_nexthop(mpath, next_hop);
Rui Paulod19b3bf2009-11-09 23:46:55 +0000832 mpath->sn = 0xffff;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100833 mpath->metric = 0;
834 mpath->hop_count = 0;
835 mpath->exp_time = 0;
836 mpath->flags |= MESH_PATH_FIXED;
837 mesh_path_activate(mpath);
838 spin_unlock_bh(&mpath->state_lock);
839 mesh_path_tx_pending(mpath);
840}
841
Bob Copeland2bdaf382016-02-28 20:03:56 -0500842int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100843{
Johannes Berg349eb8c2011-05-14 11:56:16 +0200844 struct mesh_table *tbl_path, *tbl_mpp;
Dan Carpenter4c5ade42011-08-30 22:16:15 +0300845 int ret;
YanBo79617de2008-09-22 13:30:32 +0800846
Bob Copeland60854fd2016-03-02 10:09:20 -0500847 tbl_path = mesh_table_alloc();
Johannes Berg349eb8c2011-05-14 11:56:16 +0200848 if (!tbl_path)
849 return -ENOMEM;
Javier Cardona5ee68e52011-08-09 16:45:08 -0700850
Bob Copeland60854fd2016-03-02 10:09:20 -0500851 tbl_mpp = mesh_table_alloc();
Johannes Berg349eb8c2011-05-14 11:56:16 +0200852 if (!tbl_mpp) {
Dan Carpenter4c5ade42011-08-30 22:16:15 +0300853 ret = -ENOMEM;
854 goto free_path;
YanBo79617de2008-09-22 13:30:32 +0800855 }
Johannes Berg349eb8c2011-05-14 11:56:16 +0200856
Bob Copeland60854fd2016-03-02 10:09:20 -0500857 rhashtable_init(&tbl_path->rhead, &mesh_rht_params);
858 rhashtable_init(&tbl_mpp->rhead, &mesh_rht_params);
Bob Copeland2bdaf382016-02-28 20:03:56 -0500859
Bob Copeland60854fd2016-03-02 10:09:20 -0500860 sdata->u.mesh.mesh_paths = tbl_path;
861 sdata->u.mesh.mpp_paths = tbl_mpp;
YanBo79617de2008-09-22 13:30:32 +0800862
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100863 return 0;
Dan Carpenter4c5ade42011-08-30 22:16:15 +0300864
Dan Carpenter4c5ade42011-08-30 22:16:15 +0300865free_path:
Bob Copeland60854fd2016-03-02 10:09:20 -0500866 mesh_table_free(tbl_path);
Dan Carpenter4c5ade42011-08-30 22:16:15 +0300867 return ret;
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100868}
869
Bob Copeland60854fd2016-03-02 10:09:20 -0500870static
871void mesh_path_tbl_expire(struct ieee80211_sub_if_data *sdata,
872 struct mesh_table *tbl)
873{
874 struct mesh_path *mpath;
875 struct rhashtable_iter iter;
876 int ret;
877
878 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_KERNEL);
879 if (ret)
880 return;
881
882 ret = rhashtable_walk_start(&iter);
883 if (ret && ret != -EAGAIN)
884 goto out;
885
886 while ((mpath = rhashtable_walk_next(&iter))) {
887 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
888 continue;
889 if (IS_ERR(mpath))
890 break;
891 if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
892 (!(mpath->flags & MESH_PATH_FIXED)) &&
893 time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
894 __mesh_path_del(tbl, mpath);
895 }
896out:
897 rhashtable_walk_stop(&iter);
898 rhashtable_walk_exit(&iter);
899}
900
Jasper Bryant-Greenef698d852008-08-03 12:04:37 +1200901void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100902{
Bob Copeland60854fd2016-03-02 10:09:20 -0500903 mesh_path_tbl_expire(sdata, sdata->u.mesh.mesh_paths);
904 mesh_path_tbl_expire(sdata, sdata->u.mesh.mpp_paths);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100905}
906
Bob Copeland2bdaf382016-02-28 20:03:56 -0500907void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata)
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100908{
Bob Copeland60854fd2016-03-02 10:09:20 -0500909 mesh_table_free(sdata->u.mesh.mesh_paths);
910 mesh_table_free(sdata->u.mesh.mpp_paths);
Luis Carlos Coboeb2b9312008-02-23 15:17:14 +0100911}