Commit 5ee68e5b authored by Javier Cardona's avatar Javier Cardona Committed by John W. Linville

mac80211: mesh gate implementation

In this implementation, a mesh gate is a root node with a certain bit
set in its RANN flags. The mpath to this root node is marked as a path
to a gate, and added to our list of known gates for this if_mesh. Once a
path discovery process fails, we forward the unresolved frames to a
known gate. Thanks to Luis Rodriguez for refactoring and bug fix help.
Signed-off-by: default avatarJavier Cardona <javier@cozybit.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 00e3f25c
...@@ -633,6 +633,10 @@ struct ieee80211_rann_ie { ...@@ -633,6 +633,10 @@ struct ieee80211_rann_ie {
u32 rann_metric; u32 rann_metric;
} __attribute__ ((packed)); } __attribute__ ((packed));
enum ieee80211_rann_flags {
RANN_FLAG_IS_GATE = 1 << 0,
};
#define WLAN_SA_QUERY_TR_ID_LEN 2 #define WLAN_SA_QUERY_TR_ID_LEN 2
struct ieee80211_mgmt { struct ieee80211_mgmt {
......
...@@ -514,6 +514,7 @@ struct ieee80211_if_mesh { ...@@ -514,6 +514,7 @@ struct ieee80211_if_mesh {
struct mesh_config mshcfg; struct mesh_config mshcfg;
u32 mesh_seqnum; u32 mesh_seqnum;
bool accepting_plinks; bool accepting_plinks;
int num_gates;
const u8 *ie; const u8 *ie;
u8 ie_len; u8 ie_len;
enum { enum {
......
...@@ -545,7 +545,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) ...@@ -545,7 +545,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
/* use atomic bitops in case both timers fire at the same time */ /* use atomic bitops in case all timers fire at the same time */
if (del_timer_sync(&ifmsh->housekeeping_timer)) if (del_timer_sync(&ifmsh->housekeeping_timer))
set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
...@@ -752,6 +752,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) ...@@ -752,6 +752,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
ifmsh->accepting_plinks = true; ifmsh->accepting_plinks = true;
ifmsh->preq_id = 0; ifmsh->preq_id = 0;
ifmsh->sn = 0; ifmsh->sn = 0;
ifmsh->num_gates = 0;
atomic_set(&ifmsh->mpaths, 0); atomic_set(&ifmsh->mpaths, 0);
mesh_rmc_init(sdata); mesh_rmc_init(sdata);
ifmsh->last_preq = jiffies; ifmsh->last_preq = jiffies;
......
...@@ -81,6 +81,7 @@ enum mesh_deferred_task_flags { ...@@ -81,6 +81,7 @@ enum mesh_deferred_task_flags {
* @discovery_retries: number of discovery retries * @discovery_retries: number of discovery retries
* @flags: mesh path flags, as specified on &enum mesh_path_flags * @flags: mesh path flags, as specified on &enum mesh_path_flags
* @state_lock: mesh path state lock * @state_lock: mesh path state lock
* @is_gate: the destination station of this path is a mesh gate
* *
* *
* The combination of dst and sdata is unique in the mesh path table. Since the * The combination of dst and sdata is unique in the mesh path table. Since the
...@@ -104,6 +105,7 @@ struct mesh_path { ...@@ -104,6 +105,7 @@ struct mesh_path {
u8 discovery_retries; u8 discovery_retries;
enum mesh_path_flags flags; enum mesh_path_flags flags;
spinlock_t state_lock; spinlock_t state_lock;
bool is_gate;
}; };
/** /**
...@@ -120,6 +122,9 @@ struct mesh_path { ...@@ -120,6 +122,9 @@ struct mesh_path {
* buckets * buckets
* @mean_chain_len: maximum average length for the hash buckets' list, if it is * @mean_chain_len: maximum average length for the hash buckets' list, if it is
* reached, the table will grow * reached, the table will grow
* @known_gates: list of known mesh gates and their mpaths by the station. The
* gate's mpath may or may not be resolved and active.
*
* rcu_head: RCU head to free the table * rcu_head: RCU head to free the table
*/ */
struct mesh_table { struct mesh_table {
...@@ -133,6 +138,8 @@ struct mesh_table { ...@@ -133,6 +138,8 @@ struct mesh_table {
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
int size_order; int size_order;
int mean_chain_len; int mean_chain_len;
struct hlist_head *known_gates;
spinlock_t gates_lock;
struct rcu_head rcu_head; struct rcu_head rcu_head;
}; };
...@@ -236,6 +243,10 @@ void mesh_path_flush(struct ieee80211_sub_if_data *sdata); ...@@ -236,6 +243,10 @@ void mesh_path_flush(struct ieee80211_sub_if_data *sdata);
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len); struct ieee80211_mgmt *mgmt, size_t len);
int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
int mesh_path_add_gate(struct mesh_path *mpath);
int mesh_path_send_to_gates(struct mesh_path *mpath);
int mesh_gate_num(struct ieee80211_sub_if_data *sdata);
/* Mesh plinks */ /* Mesh plinks */
void mesh_neighbour_update(u8 *hw_addr, u32 rates, void mesh_neighbour_update(u8 *hw_addr, u32 rates,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
......
...@@ -696,6 +696,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -696,6 +696,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
u8 *orig_addr; u8 *orig_addr;
u32 orig_sn, metric; u32 orig_sn, metric;
u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL); u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
bool root_is_gate;
ttl = rann->rann_ttl; ttl = rann->rann_ttl;
if (ttl <= 1) { if (ttl <= 1) {
...@@ -704,12 +705,19 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -704,12 +705,19 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
} }
ttl--; ttl--;
flags = rann->rann_flags; flags = rann->rann_flags;
root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
orig_addr = rann->rann_addr; orig_addr = rann->rann_addr;
orig_sn = rann->rann_seq; orig_sn = rann->rann_seq;
hopcount = rann->rann_hopcount; hopcount = rann->rann_hopcount;
hopcount++; hopcount++;
metric = rann->rann_metric; metric = rann->rann_metric;
mhwmp_dbg("received RANN from %pM\n", orig_addr);
/* Ignore our own RANNs */
if (memcmp(orig_addr, sdata->vif.addr, ETH_ALEN) == 0)
return;
mhwmp_dbg("received RANN from %pM (is_gate=%d)", orig_addr,
root_is_gate);
rcu_read_lock(); rcu_read_lock();
mpath = mesh_path_lookup(orig_addr, sdata); mpath = mesh_path_lookup(orig_addr, sdata);
...@@ -721,9 +729,16 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -721,9 +729,16 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
sdata->u.mesh.mshstats.dropped_frames_no_route++; sdata->u.mesh.mshstats.dropped_frames_no_route++;
return; return;
} }
mesh_queue_preq(mpath,
PREQ_Q_F_START | PREQ_Q_F_REFRESH);
} }
if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) ||
time_after(jiffies, mpath->exp_time - 1*HZ)) &&
!(mpath->flags & MESH_PATH_FIXED)) {
mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name,
orig_addr);
mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
}
if (mpath->sn < orig_sn) { if (mpath->sn < orig_sn) {
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
cpu_to_le32(orig_sn), cpu_to_le32(orig_sn),
...@@ -733,6 +748,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -733,6 +748,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
0, sdata); 0, sdata);
mpath->sn = orig_sn; mpath->sn = orig_sn;
} }
if (root_is_gate)
mesh_path_add_gate(mpath);
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -994,25 +1012,32 @@ void mesh_path_timer(unsigned long data) ...@@ -994,25 +1012,32 @@ void mesh_path_timer(unsigned long data)
{ {
struct mesh_path *mpath = (void *) data; struct mesh_path *mpath = (void *) data;
struct ieee80211_sub_if_data *sdata = mpath->sdata; struct ieee80211_sub_if_data *sdata = mpath->sdata;
int ret;
if (sdata->local->quiescing) if (sdata->local->quiescing)
return; return;
spin_lock_bh(&mpath->state_lock); spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_RESOLVED || if (mpath->flags & MESH_PATH_RESOLVED ||
(!(mpath->flags & MESH_PATH_RESOLVING))) (!(mpath->flags & MESH_PATH_RESOLVING))) {
mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
else if (mpath->discovery_retries < max_preq_retries(sdata)) { spin_unlock_bh(&mpath->state_lock);
} else if (mpath->discovery_retries < max_preq_retries(sdata)) {
++mpath->discovery_retries; ++mpath->discovery_retries;
mpath->discovery_timeout *= 2; mpath->discovery_timeout *= 2;
spin_unlock_bh(&mpath->state_lock);
mesh_queue_preq(mpath, 0); mesh_queue_preq(mpath, 0);
} else { } else {
mpath->flags = 0; mpath->flags = 0;
mpath->exp_time = jiffies; mpath->exp_time = jiffies;
spin_unlock_bh(&mpath->state_lock);
if (!mpath->is_gate && mesh_gate_num(sdata) > 0) {
ret = mesh_path_send_to_gates(mpath);
if (ret)
mhwmp_dbg("no gate was reachable");
} else
mesh_path_flush_pending(mpath); mesh_path_flush_pending(mpath);
} }
spin_unlock_bh(&mpath->state_lock);
} }
void void
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment