2011-08-09 23:46:23

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 0/8] mac80211: add mesh gate forwarding

Javier Cardona (8):
mac80211: improve mpath debugging
mac80211: fix mpath timer NULL function
mac80211: mesh locking fixes
mac80211: fix mesh path flushing
mac80211: mesh gate implementation
{nl,mac}80211: add missing root mode meshconf entries
{nl,cfg,mac}80211: let userspace set RANN interval
{nl,cfg,mac}80211: let userspace make meshif mesh gate

include/linux/ieee80211.h | 4 +
include/linux/nl80211.h | 9 ++
include/net/cfg80211.h | 6 +
net/mac80211/Kconfig | 13 ++
net/mac80211/cfg.c | 8 +
net/mac80211/debugfs_netdev.c | 8 +-
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mesh.c | 6 +-
net/mac80211/mesh.h | 12 ++-
net/mac80211/mesh_hwmp.c | 77 +++++++----
net/mac80211/mesh_pathtbl.c | 303 ++++++++++++++++++++++++++++++++++++++++-
net/wireless/mesh.c | 3 +
net/wireless/nl80211.c | 15 ++
13 files changed, 431 insertions(+), 34 deletions(-)

--
1.7.6



2011-08-10 13:48:01

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 8/8] {nl,cfg,mac}80211: let userspace make meshif mesh gate

On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:
> From: Javier Cardona <[email protected]>
>
> Allow userspace to set NL80211_MESHCONF_GATE_ANNOUNCEMENTS attribute,
> which will advertise this mesh node as being a mesh gate.
> NL80211_HWMP_ROOTMODE must be set or this will do nothing.

IMHO it should be rejected instead of doing nothing.

johannes


2011-08-22 18:45:10

by John W. Linville

[permalink] [raw]
Subject: Re: [PATCH v2 1/8] mac80211: improve mpath debugging

On Fri, Aug 12, 2011 at 11:12:08AM -0700, Thomas Pedersen wrote:
> On Fri, Aug 12, 2011 at 5:28 AM, Johannes Berg
> <[email protected]> wrote:

> > Definitely want the format attribute, that was my whole point :)
>
> Oh I see. Looking at it again, my function above doesn't even have any
> argument checking :P. Didn't know about that __attribute__ etiher,
> thanks!
>
> > Bah, maybe it all doesn't matter, in which case maybe the first version
> > is better.
>
> Sure, let's go with the first one.

OK, I'm confused -- do we want to merge the versions posted on
9 August? Or the ones from 11 August? Or...?

John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.

2011-08-12 19:03:23

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 8/8] {nl,cfg,mac}80211: let userspace make meshif mesh gate

On Fri, 2011-08-12 at 12:00 -0700, Thomas Pedersen wrote:

> iw mesh0 set mesh_param mesh_hwmp_rootmode=1
> iw mesh0 set mesh_param mesh_gate_announcements=1
>
> And the connection between the two would only be apparent to someone
> familiar with our limited implementation. So in v2, it's enough to
> just enable mesh gate announcements and root mode will be turned on
> automagically. This gets sort of ugly if say you turn off root mode
> and still expect gate announcements to work, or disable gate
> announcements and now you're still broadcasting as a root node for
> some reason. (we can't really just disable root mode when we turn of
> gate announcements, since the two should be independent). That said,
> this seems preferable to someone doing 'iw mesh0 set mesh_param
> mesh_gate_announcements=1', and then spending an inordinate time
> debugging when it should just work.

Hmm. I wonder if it then makes sense to allow changing this on the fly
at all?

johannes


2011-08-12 02:54:16

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 2/8] mac80211: fix mpath timer removal

From: Javier Cardona <[email protected]>

Initialize mpath timers added to mpp_table.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 3ce6c85..7d050af 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -503,6 +503,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
new_mpath->flags = 0;
skb_queue_head_init(&new_mpath->frame_queue);
new_node->mpath = new_mpath;
+ init_timer(&new_mpath->timer);
new_mpath->exp_time = jiffies;
spin_lock_init(&new_mpath->state_lock);

--
1.7.4.1


2011-08-12 19:00:44

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH 8/8] {nl,cfg,mac}80211: let userspace make meshif mesh gate

On Fri, Aug 12, 2011 at 2:31 AM, Johannes Berg
<[email protected]> wrote:
> On Wed, 2011-08-10 at 14:31 -0700, Thomas Pedersen wrote:
>> On Wed, Aug 10, 2011 at 6:47 AM, Johannes Berg
>> <[email protected]> wrote:
>> > On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:
>> >> From: Javier Cardona <[email protected]>
>> >>
>> >> Allow userspace to set NL80211_MESHCONF_GATE_ANNOUNCEMENTS attribute,
>> >> which will advertise this mesh node as being a mesh gate.
>> >> NL80211_HWMP_ROOTMODE must be set or this will do nothing.
>> >
>> > IMHO it should be rejected instead of doing nothing.
>> >
>> Maybe the "right thing" to do is not require the user to know anything
>> about the limitations of our implementation, and instead just enable
>> root mode as needed?
>
> I don't know? Is it a limitation of the implementation? I know
> practically nothing about mesh :-) It just didn't seem right to silently
> ignore something.

Currently we're setting a bit in the Root Announcement (RANN) frames
indicating "this root node is also a mesh gate". Obviously this
requires the mesh gate to also be a root node. There is a separate
Gate Announcement (GANN) protocol in the standard which allows you to
define these two separately, but it's not currently implemented. So in
v1 of the patch, you would have to do something like:

iw mesh0 set mesh_param mesh_hwmp_rootmode=1
iw mesh0 set mesh_param mesh_gate_announcements=1

And the connection between the two would only be apparent to someone
familiar with our limited implementation. So in v2, it's enough to
just enable mesh gate announcements and root mode will be turned on
automagically. This gets sort of ugly if say you turn off root mode
and still expect gate announcements to work, or disable gate
announcements and now you're still broadcasting as a root node for
some reason. (we can't really just disable root mode when we turn of
gate announcements, since the two should be independent). That said,
this seems preferable to someone doing 'iw mesh0 set mesh_param
mesh_gate_announcements=1', and then spending an inordinate time
debugging when it should just work.

Of course the correct thing to do would be implement the GANN
protocol, and then we wouldn't have to go behind the user's back., but
this would require significantly more work. The v2 works for now, and
does the expected thing as long as you weren't expecting us to enable
root mode (arrrgh! what was that thing about mechanism vs. policy?).

Consider this patchset as implementing 2/3 of mesh gate functionality
and papering over the last 1/3. Of course if you feel strongly about
this either way, just let me know and I'll make the appropriate
changes.

Thanks,
Thomas

2011-08-09 23:46:31

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 6/8] {nl,mac}80211: add missing root mode meshconf entries

From: Javier Cardona <[email protected]>

This fix allows userspace to mark a meshif as a root node.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/debugfs_netdev.c | 2 +-
net/wireless/nl80211.c | 1 +
2 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9ea7c0d..75ece3d 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -485,7 +485,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
MESHPARAMS_ADD(path_refresh_time);
MESHPARAMS_ADD(min_discovery_timeout);
-
+ MESHPARAMS_ADD(dot11MeshHWMPRootMode);
#undef MESHPARAMS_ADD
}
#endif
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e83e7fe..c7b5e44 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2982,6 +2982,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
};

static const struct nla_policy
--
1.7.6


2011-08-10 20:11:27

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH 1/8] mac80211: improve mpath debugging

On Wed, Aug 10, 2011 at 6:38 AM, Johannes Berg
<[email protected]> wrote:
> On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:
>
>> +#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
>
> Maybe this should be a static inline for checking the fmt args even when
> it's compiled out?
>
I don't really see the point, since all this would give us is the
compiler checking whether a const char * was passed as an argument to
fmt, right?
> johannes
>
>

2011-08-10 13:41:35

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 5/8] mac80211: mesh gate implementation

On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:

> tbl_mpp->copy_node = &mesh_path_node_copy;
> tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
> + /* XXX: not needed */
> + tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
> + INIT_HLIST_HEAD(tbl_mpp->known_gates);

?

johannes


2011-08-12 19:27:14

by Javier Cardona

[permalink] [raw]
Subject: Re: [PATCH 8/8] {nl,cfg,mac}80211: let userspace make meshif mesh gate

On Fri, Aug 12, 2011 at 12:03 PM, Johannes Berg
<[email protected]> wrote:
> On Fri, 2011-08-12 at 12:00 -0700, Thomas Pedersen wrote:
>
>> iw mesh0 set mesh_param mesh_hwmp_rootmode=1
>> iw mesh0 set mesh_param mesh_gate_announcements=1
>>
>> And the connection between the two would only be apparent to someone
>> familiar with our limited implementation.

The draft defines three different ways to advertise gate over the
mesh, leaving the implementers choice of which one(s) to implement.
We chose the one that was best suited for the most common usage
scenario. I would not call that a limited implementation but rather
"an efficient implementation of a bloated spec" :)

> Hmm. I wonder if it then makes sense to allow changing this on the fly
> at all?

Yes it does. Gate announcements should only go out if a node has some
other interface connected to an external network. If the external
interface goes down, one would want to stop gate announcements
immediately without bringing down the mesh interface.

Javier



--
Javier Cardona
cozybit Inc.
http://www.cozybit.com

2011-08-09 23:46:31

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 5/8] mac80211: mesh gate implementation

From: Javier Cardona <[email protected]>

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: Javier Cardona <[email protected]>
---
include/linux/ieee80211.h | 4 +
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mesh.c | 3 +-
net/mac80211/mesh.h | 11 ++
net/mac80211/mesh_hwmp.c | 41 +++++--
net/mac80211/mesh_pathtbl.c | 284 +++++++++++++++++++++++++++++++++++++++++++
6 files changed, 335 insertions(+), 9 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index db6c359..1ac50a7 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -633,6 +633,10 @@ struct ieee80211_rann_ie {
u32 rann_metric;
} __attribute__ ((packed));

+enum ieee80211_rann_flags {
+ RANN_FLAG_IS_GATE = 1 << 0,
+};
+
#define WLAN_SA_QUERY_TR_ID_LEN 2

struct ieee80211_mgmt {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ef68aa8..57d6ff0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -514,6 +514,7 @@ struct ieee80211_if_mesh {
struct mesh_config mshcfg;
u32 mesh_seqnum;
bool accepting_plinks;
+ int num_gates;
const u8 *ie;
u8 ie_len;
enum {
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index ecdde6c..e120fef 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -545,7 +545,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
{
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))
set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -752,6 +752,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
ifmsh->accepting_plinks = true;
ifmsh->preq_id = 0;
ifmsh->sn = 0;
+ ifmsh->num_gates = 0;
atomic_set(&ifmsh->mpaths, 0);
mesh_rmc_init(sdata);
ifmsh->last_preq = jiffies;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 3c7d0f8..9d9116e 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -81,6 +81,7 @@ enum mesh_deferred_task_flags {
* @discovery_retries: number of discovery retries
* @flags: mesh path flags, as specified on &enum mesh_path_flags
* @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
@@ -104,6 +105,7 @@ struct mesh_path {
u8 discovery_retries;
enum mesh_path_flags flags;
spinlock_t state_lock;
+ bool is_gate;
};

/**
@@ -120,6 +122,9 @@ struct mesh_path {
* buckets
* @mean_chain_len: maximum average length for the hash buckets' list, if it is
* 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
*/
struct mesh_table {
@@ -133,6 +138,8 @@ struct mesh_table {
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
int size_order;
int mean_chain_len;
+ struct hlist_head *known_gates;
+ spinlock_t gates_lock;

struct rcu_head rcu_head;
};
@@ -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,
struct ieee80211_mgmt *mgmt, size_t len);
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 */
void mesh_neighbour_update(u8 *hw_addr, u32 rates,
struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 14803ae..d14dfe4 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -695,6 +695,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
u8 *orig_addr;
u32 orig_sn, metric;
u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
+ bool root_is_gate;

ttl = rann->rann_ttl;
if (ttl <= 1) {
@@ -703,12 +704,19 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
}
ttl--;
flags = rann->rann_flags;
+ root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
orig_addr = rann->rann_addr;
orig_sn = rann->rann_seq;
hopcount = rann->rann_hopcount;
hopcount++;
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();
mpath = mesh_path_lookup(orig_addr, sdata);
@@ -720,9 +728,16 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
sdata->u.mesh.mshstats.dropped_frames_no_route++;
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) {
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
cpu_to_le32(orig_sn),
@@ -732,6 +747,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
0, sdata);
mpath->sn = orig_sn;
}
+ if (root_is_gate)
+ mesh_path_add_gate(mpath);
+
rcu_read_unlock();
}

@@ -993,25 +1011,32 @@ void mesh_path_timer(unsigned long data)
{
struct mesh_path *mpath = (void *) data;
struct ieee80211_sub_if_data *sdata = mpath->sdata;
+ int ret;

if (sdata->local->quiescing)
return;

spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_RESOLVED ||
- (!(mpath->flags & MESH_PATH_RESOLVING)))
+ (!(mpath->flags & MESH_PATH_RESOLVING))) {
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_timeout *= 2;
+ spin_unlock_bh(&mpath->state_lock);
mesh_queue_preq(mpath, 0);
} else {
mpath->flags = 0;
mpath->exp_time = jiffies;
- mesh_path_flush_pending(mpath);
+ 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);
}
-
- spin_unlock_bh(&mpath->state_lock);
}

void
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index de8c4f6..85806e7 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -66,6 +66,8 @@ static inline struct mesh_table *resize_dereference_mpp_paths(void)
lockdep_is_held(&pathtbl_resize_lock));
}

+static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath);
+
/*
* CAREFUL -- "tbl" must not be an expression,
* in particular not an rcu_dereference(), since
@@ -109,6 +111,7 @@ static struct mesh_table *mesh_table_alloc(int size_order)
sizeof(newtbl->hash_rnd));
for (i = 0; i <= newtbl->hash_mask; i++)
spin_lock_init(&newtbl->hashwlock[i]);
+ spin_lock_init(&newtbl->gates_lock);

return newtbl;
}
@@ -124,6 +127,7 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
{
struct hlist_head *mesh_hash;
struct hlist_node *p, *q;
+ struct mpath_node *gate;
int i;

mesh_hash = tbl->hash_buckets;
@@ -135,6 +139,17 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
}
spin_unlock_bh(&tbl->hashwlock[i]);
}
+ 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);
+ }
+
__mesh_table_free(tbl);
}

@@ -152,6 +167,7 @@ static int mesh_table_grow(struct mesh_table *oldtbl,
newtbl->free_node = oldtbl->free_node;
newtbl->mean_chain_len = oldtbl->mean_chain_len;
newtbl->copy_node = oldtbl->copy_node;
+ newtbl->known_gates = oldtbl->known_gates;
atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));

oldhash = oldtbl->hash_buckets;
@@ -211,6 +227,111 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
}

+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();
+ 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)
+{
+ struct sk_buff *skb, *cp_skb;
+ 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);
+ if (copy)
+ cp_skb = skb_copy(skb, GFP_ATOMIC);
+
+ prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
+ __skb_queue_tail(&gateq, skb);
+
+ if (copy && cp_skb)
+ __skb_queue_tail(&failq, cp_skb);
+ }
+
+ 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\n",
+ 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);
+}
+

/**
* mesh_path_lookup - look up a path in the mesh path table
@@ -310,6 +431,109 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
return NULL;
}

+static void mesh_gate_node_reclaim(struct rcu_head *rp)
+{
+ struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
+ kfree(node);
+}
+
+/**
+ * mesh_gate_add - mark mpath as path to a mesh gate and add to known_gates
+ * @mesh_tbl: table which contains known_gates list
+ * @mpath: mpath to known mesh gate
+ *
+ * Returns: 0 on success
+ *
+ */
+static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath)
+{
+ struct mpath_node *gate, *new_gate;
+ struct hlist_node *n;
+ int err;
+
+ rcu_read_lock();
+ tbl = rcu_dereference(tbl);
+
+ 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\n",
+ 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;
+
+ tbl = rcu_dereference(tbl);
+
+ 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\n", mpath->sdata->name,
+ mpath->dst, mpath->sdata->u.mesh.num_gates);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ *
+ * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
+ * @mpath: gate path to add to table
+ */
+int mesh_path_add_gate(struct mesh_path *mpath)
+{
+ return mesh_gate_add(mesh_paths, mpath);
+}
+
+/**
+ * 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;
+}
+
/**
* mesh_path_add - allocate and add a new path to the mesh path table
* @addr: destination address of the path (ETH_ALEN length)
@@ -655,6 +879,8 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
if (mpath->sdata == sdata &&
memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
spin_lock_bh(&mpath->state_lock);
+ if (mpath->is_gate)
+ mesh_gate_del(tbl, mpath);
mpath->flags |= MESH_PATH_RESOLVING;
hlist_del_rcu(&node->list);
call_rcu(&node->rcu, mesh_path_node_reclaim);
@@ -688,6 +914,58 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
}

/**
+ * 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\n", 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\n", gate->mpath);
+ mpath_dbg("flags %x\n", gate->mpath->flags);
+ }
+ }
+
+ hlist_for_each_entry_rcu(gate, n, known_gates, list)
+ if (gate->mpath->sdata == sdata) {
+ mpath_dbg("Sending to %pM\n", gate->mpath->dst);
+ mesh_path_tx_pending(gate->mpath);
+ }
+
+ return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
+}
+
+/**
* mesh_path_discard_frame - discard a frame whose path could not be resolved
*
* @skb: frame to discard
@@ -804,6 +1082,9 @@ int mesh_pathtbl_init(void)
tbl_path->free_node = &mesh_path_node_free;
tbl_path->copy_node = &mesh_path_node_copy;
tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
+ tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
+ INIT_HLIST_HEAD(tbl_path->known_gates);
+

tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
if (!tbl_mpp) {
@@ -813,6 +1094,9 @@ int mesh_pathtbl_init(void)
tbl_mpp->free_node = &mesh_path_node_free;
tbl_mpp->copy_node = &mesh_path_node_copy;
tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
+ /* XXX: not needed */
+ tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
+ INIT_HLIST_HEAD(tbl_mpp->known_gates);

/* Need no locking since this is during init */
RCU_INIT_POINTER(mesh_paths, tbl_path);
--
1.7.6


2011-08-12 02:54:22

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 5/8] mac80211: mesh gate implementation

From: Javier Cardona <[email protected]>

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: Javier Cardona <[email protected]>
Signed-off-by: Thomas Pedersen <[email protected]>

---
include/linux/ieee80211.h | 4 +
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mesh.c | 3 +-
net/mac80211/mesh.h | 11 ++
net/mac80211/mesh_hwmp.c | 41 +++++--
net/mac80211/mesh_pathtbl.c | 283 +++++++++++++++++++++++++++++++++++++++++++
6 files changed, 334 insertions(+), 9 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index db6c359..1ac50a7 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -633,6 +633,10 @@ struct ieee80211_rann_ie {
u32 rann_metric;
} __attribute__ ((packed));

+enum ieee80211_rann_flags {
+ RANN_FLAG_IS_GATE = 1 << 0,
+};
+
#define WLAN_SA_QUERY_TR_ID_LEN 2

struct ieee80211_mgmt {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ef68aa8..57d6ff0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -514,6 +514,7 @@ struct ieee80211_if_mesh {
struct mesh_config mshcfg;
u32 mesh_seqnum;
bool accepting_plinks;
+ int num_gates;
const u8 *ie;
u8 ie_len;
enum {
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index ecdde6c..e120fef 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -545,7 +545,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
{
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))
set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -752,6 +752,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
ifmsh->accepting_plinks = true;
ifmsh->preq_id = 0;
ifmsh->sn = 0;
+ ifmsh->num_gates = 0;
atomic_set(&ifmsh->mpaths, 0);
mesh_rmc_init(sdata);
ifmsh->last_preq = jiffies;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 3c7d0f8..9d9116e 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -81,6 +81,7 @@ enum mesh_deferred_task_flags {
* @discovery_retries: number of discovery retries
* @flags: mesh path flags, as specified on &enum mesh_path_flags
* @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
@@ -104,6 +105,7 @@ struct mesh_path {
u8 discovery_retries;
enum mesh_path_flags flags;
spinlock_t state_lock;
+ bool is_gate;
};

/**
@@ -120,6 +122,9 @@ struct mesh_path {
* buckets
* @mean_chain_len: maximum average length for the hash buckets' list, if it is
* 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
*/
struct mesh_table {
@@ -133,6 +138,8 @@ struct mesh_table {
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
int size_order;
int mean_chain_len;
+ struct hlist_head *known_gates;
+ spinlock_t gates_lock;

struct rcu_head rcu_head;
};
@@ -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,
struct ieee80211_mgmt *mgmt, size_t len);
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 */
void mesh_neighbour_update(u8 *hw_addr, u32 rates,
struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index abd0347..7b517c4 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -696,6 +696,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
u8 *orig_addr;
u32 orig_sn, metric;
u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
+ bool root_is_gate;

ttl = rann->rann_ttl;
if (ttl <= 1) {
@@ -704,12 +705,19 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
}
ttl--;
flags = rann->rann_flags;
+ root_is_gate = !!(flags & RANN_FLAG_IS_GATE);
orig_addr = rann->rann_addr;
orig_sn = rann->rann_seq;
hopcount = rann->rann_hopcount;
hopcount++;
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();
mpath = mesh_path_lookup(orig_addr, 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++;
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) {
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
cpu_to_le32(orig_sn),
@@ -733,6 +748,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
0, sdata);
mpath->sn = orig_sn;
}
+ if (root_is_gate)
+ mesh_path_add_gate(mpath);
+
rcu_read_unlock();
}

@@ -994,25 +1012,32 @@ void mesh_path_timer(unsigned long data)
{
struct mesh_path *mpath = (void *) data;
struct ieee80211_sub_if_data *sdata = mpath->sdata;
+ int ret;

if (sdata->local->quiescing)
return;

spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_RESOLVED ||
- (!(mpath->flags & MESH_PATH_RESOLVING)))
+ (!(mpath->flags & MESH_PATH_RESOLVING))) {
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_timeout *= 2;
+ spin_unlock_bh(&mpath->state_lock);
mesh_queue_preq(mpath, 0);
} else {
mpath->flags = 0;
mpath->exp_time = jiffies;
- mesh_path_flush_pending(mpath);
+ 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);
}
-
- spin_unlock_bh(&mpath->state_lock);
}

void
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index b5f2a14..1ca61b6 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -82,6 +82,8 @@ static inline struct mesh_table *resize_dereference_mpp_paths(void)
lockdep_is_held(&pathtbl_resize_lock));
}

+static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath);
+
/*
* CAREFUL -- "tbl" must not be an expression,
* in particular not an rcu_dereference(), since
@@ -125,6 +127,7 @@ static struct mesh_table *mesh_table_alloc(int size_order)
sizeof(newtbl->hash_rnd));
for (i = 0; i <= newtbl->hash_mask; i++)
spin_lock_init(&newtbl->hashwlock[i]);
+ spin_lock_init(&newtbl->gates_lock);

return newtbl;
}
@@ -140,6 +143,7 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
{
struct hlist_head *mesh_hash;
struct hlist_node *p, *q;
+ struct mpath_node *gate;
int i;

mesh_hash = tbl->hash_buckets;
@@ -151,6 +155,17 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
}
spin_unlock_bh(&tbl->hashwlock[i]);
}
+ 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);
+ }
+
__mesh_table_free(tbl);
}

@@ -168,6 +183,7 @@ static int mesh_table_grow(struct mesh_table *oldtbl,
newtbl->free_node = oldtbl->free_node;
newtbl->mean_chain_len = oldtbl->mean_chain_len;
newtbl->copy_node = oldtbl->copy_node;
+ newtbl->known_gates = oldtbl->known_gates;
atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));

oldhash = oldtbl->hash_buckets;
@@ -227,6 +243,111 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
}

+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();
+ 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)
+{
+ struct sk_buff *skb, *cp_skb = NULL;
+ 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);
+ if (copy)
+ cp_skb = skb_copy(skb, GFP_ATOMIC);
+
+ prepare_for_gate(skb, gate_mpath->dst, gate_mpath);
+ __skb_queue_tail(&gateq, skb);
+
+ if (copy && cp_skb)
+ __skb_queue_tail(&failq, cp_skb);
+ }
+
+ 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\n",
+ 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);
+}
+

/**
* mesh_path_lookup - look up a path in the mesh path table
@@ -326,6 +447,109 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
return NULL;
}

+static void mesh_gate_node_reclaim(struct rcu_head *rp)
+{
+ struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
+ kfree(node);
+}
+
+/**
+ * mesh_gate_add - mark mpath as path to a mesh gate and add to known_gates
+ * @mesh_tbl: table which contains known_gates list
+ * @mpath: mpath to known mesh gate
+ *
+ * Returns: 0 on success
+ *
+ */
+static int mesh_gate_add(struct mesh_table *tbl, struct mesh_path *mpath)
+{
+ struct mpath_node *gate, *new_gate;
+ struct hlist_node *n;
+ int err;
+
+ rcu_read_lock();
+ tbl = rcu_dereference(tbl);
+
+ 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\n",
+ 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;
+
+ tbl = rcu_dereference(tbl);
+
+ 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\n", mpath->sdata->name,
+ mpath->dst, mpath->sdata->u.mesh.num_gates);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ *
+ * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
+ * @mpath: gate path to add to table
+ */
+int mesh_path_add_gate(struct mesh_path *mpath)
+{
+ return mesh_gate_add(mesh_paths, mpath);
+}
+
+/**
+ * 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;
+}
+
/**
* mesh_path_add - allocate and add a new path to the mesh path table
* @addr: destination address of the path (ETH_ALEN length)
@@ -671,6 +895,8 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
if (mpath->sdata == sdata &&
memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
spin_lock_bh(&mpath->state_lock);
+ if (mpath->is_gate)
+ mesh_gate_del(tbl, mpath);
mpath->flags |= MESH_PATH_RESOLVING;
hlist_del_rcu(&node->list);
call_rcu(&node->rcu, mesh_path_node_reclaim);
@@ -704,6 +930,58 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
}

/**
+ * 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\n", 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\n", gate->mpath);
+ mpath_dbg("flags %x\n", gate->mpath->flags);
+ }
+ }
+
+ hlist_for_each_entry_rcu(gate, n, known_gates, list)
+ if (gate->mpath->sdata == sdata) {
+ mpath_dbg("Sending to %pM\n", gate->mpath->dst);
+ mesh_path_tx_pending(gate->mpath);
+ }
+
+ return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
+}
+
+/**
* mesh_path_discard_frame - discard a frame whose path could not be resolved
*
* @skb: frame to discard
@@ -819,6 +1097,9 @@ int mesh_pathtbl_init(void)
tbl_path->free_node = &mesh_path_node_free;
tbl_path->copy_node = &mesh_path_node_copy;
tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
+ tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
+ INIT_HLIST_HEAD(tbl_path->known_gates);
+

tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
if (!tbl_mpp) {
@@ -828,6 +1109,8 @@ int mesh_pathtbl_init(void)
tbl_mpp->free_node = &mesh_path_node_free;
tbl_mpp->copy_node = &mesh_path_node_copy;
tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
+ tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
+ INIT_HLIST_HEAD(tbl_mpp->known_gates);

/* Need no locking since this is during init */
RCU_INIT_POINTER(mesh_paths, tbl_path);
--
1.7.4.1


2011-08-12 02:54:14

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 1/8] mac80211: improve mpath debugging

From: Javier Cardona <[email protected]>

make hwmp_dbg print the relevant sdata->name by default and improve
formatting. Also add mpath_dbg function for debugging of mesh path
operations.

Signed-off-by: Javier Cardona <[email protected]>

---
v2:
- make mpath_dbg a function (Johannes)

net/mac80211/Kconfig | 13 +++++++++++++
net/mac80211/mesh_hwmp.c | 23 ++++++++++++-----------
net/mac80211/mesh_pathtbl.c | 22 ++++++++++++++++++++++
3 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index f5fdfcb..d1886b5 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -199,6 +199,19 @@ config MAC80211_VERBOSE_MPL_DEBUG

Do not select this option.

+config MAC80211_VERBOSE_MPATH_DEBUG
+ bool "Verbose mesh path debugging"
+ depends on MAC80211_DEBUG_MENU
+ depends on MAC80211_MESH
+ ---help---
+ Selecting this option causes mac80211 to print out very
+ verbose mesh path selection debugging messages (when mac80211
+ is taking part in a mesh network).
+ It should not be selected on production systems as those
+ messages are remotely triggerable.
+
+ Do not select this option.
+
config MAC80211_VERBOSE_MHWMP_DEBUG
bool "Verbose mesh HWMP routing debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 9c3c0b8..abd0347 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -11,7 +11,8 @@
#include "mesh.h"

#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
-#define mhwmp_dbg(fmt, args...) printk(KERN_DEBUG "Mesh HWMP: " fmt, ##args)
+#define mhwmp_dbg(fmt, args...) \
+ printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
#else
#define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
@@ -138,19 +139,19 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,

switch (action) {
case MPATH_PREQ:
- mhwmp_dbg("sending PREQ to %pM\n", target);
+ mhwmp_dbg("sending PREQ to %pM", target);
ie_len = 37;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PREQ;
break;
case MPATH_PREP:
- mhwmp_dbg("sending PREP to %pM\n", target);
+ mhwmp_dbg("sending PREP to %pM", target);
ie_len = 31;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PREP;
break;
case MPATH_RANN:
- mhwmp_dbg("sending RANN from %pM\n", orig_addr);
+ mhwmp_dbg("sending RANN from %pM", orig_addr);
ie_len = sizeof(struct ieee80211_rann_ie);
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_RANN;
@@ -494,10 +495,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
orig_sn = PREQ_IE_ORIG_SN(preq_elem);
target_flags = PREQ_IE_TARGET_F(preq_elem);

- mhwmp_dbg("received PREQ from %pM\n", orig_addr);
+ mhwmp_dbg("received PREQ from %pM", orig_addr);

if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
- mhwmp_dbg("PREQ is for us\n");
+ mhwmp_dbg("PREQ is for us");
forward = false;
reply = true;
metric = 0;
@@ -533,7 +534,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
lifetime = PREQ_IE_LIFETIME(preq_elem);
ttl = ifmsh->mshcfg.element_ttl;
if (ttl != 0) {
- mhwmp_dbg("replying to the PREQ\n");
+ mhwmp_dbg("replying to the PREQ");
mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr,
cpu_to_le32(target_sn), 0, orig_addr,
cpu_to_le32(orig_sn), mgmt->sa, 0, ttl,
@@ -553,7 +554,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
ifmsh->mshstats.dropped_frames_ttl++;
return;
}
- mhwmp_dbg("forwarding the PREQ from %pM\n", orig_addr);
+ mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
--ttl;
flags = PREQ_IE_FLAGS(preq_elem);
preq_id = PREQ_IE_PREQ_ID(preq_elem);
@@ -588,7 +589,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
u8 next_hop[ETH_ALEN];
u32 target_sn, orig_sn, lifetime;

- mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem));
+ mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));

/* Note that we divert from the draft nomenclature and denominate
* destination to what the draft refers to as origininator. So in this
@@ -799,7 +800,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)

preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
if (!preq_node) {
- mhwmp_dbg("could not allocate PREQ node\n");
+ mhwmp_dbg("could not allocate PREQ node");
return;
}

@@ -808,7 +809,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
kfree(preq_node);
if (printk_ratelimit())
- mhwmp_dbg("PREQ node queue full\n");
+ mhwmp_dbg("PREQ node queue full");
return;
}

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 6ffcd53..3ce6c85 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -17,6 +17,28 @@
#include "ieee80211_i.h"
#include "mesh.h"

+#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
+static inline void mpath_dbg(const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk(KERN_DEBUG "%pV", &vaf);
+ va_end(args);
+ return;
+}
+#else
+static inline void mpath_dbg(const char *fmt, ...)
+{
+ return;
+}
+#endif
+
/* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
#define INIT_PATHS_SIZE_ORDER 2

--
1.7.4.1


2011-08-12 02:54:20

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 4/8] mac80211: fix mesh path flushing

From: Javier Cardona <[email protected]>

Previously, mpaths were never flushed since the mpath is not active once
we call this function.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 0d80d7d..b5f2a14 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -751,8 +751,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath)
{
struct sk_buff *skb;

- while ((skb = skb_dequeue(&mpath->frame_queue)) &&
- (mpath->flags & MESH_PATH_ACTIVE))
+ while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
mesh_path_discard_frame(skb, mpath->sdata);
}

--
1.7.4.1


2011-08-12 02:54:24

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 6/8] {nl,mac}80211: add missing root mode debugfs entries

From: Javier Cardona <[email protected]>

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/debugfs_netdev.c | 2 +-
net/wireless/nl80211.c | 1 +
2 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9ea7c0d..75ece3d 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -485,7 +485,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
MESHPARAMS_ADD(path_refresh_time);
MESHPARAMS_ADD(min_discovery_timeout);
-
+ MESHPARAMS_ADD(dot11MeshHWMPRootMode);
#undef MESHPARAMS_ADD
}
#endif
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ca76977..cd5994f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2985,6 +2985,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
};

static const struct nla_policy
--
1.7.4.

2011-08-09 23:46:34

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 7/8] {nl,cfg,mac}80211: let userspace set RANN interval

From: Javier Cardona <[email protected]>

Allow userspace to set Root Announcement Interval for our mesh
interface. Also, RANN interval is now in proper units of TUs.

Signed-off-by: Javier Cardona <[email protected]>
---
include/linux/nl80211.h | 4 ++++
include/net/cfg80211.h | 1 +
net/mac80211/cfg.c | 4 ++++
net/mac80211/debugfs_netdev.c | 3 +++
net/mac80211/mesh.c | 3 ++-
net/mac80211/mesh.h | 1 -
net/mac80211/mesh_hwmp.c | 8 ++++----
net/wireless/mesh.c | 2 ++
net/wireless/nl80211.c | 7 +++++++
9 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 8ad70dc..63ad64b 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1833,6 +1833,9 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
* source mesh point for path selection elements.
*
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between
+ * root announcements are transmitted.
+ *
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -1854,6 +1857,7 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
NL80211_MESHCONF_HWMP_ROOTMODE,
NL80211_MESHCONF_ELEMENT_TTL,
+ NL80211_MESHCONF_HWMP_RANN_INTERVAL,

/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 44e72cc..207e508 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -683,6 +683,7 @@ struct mesh_config {
u16 dot11MeshHWMPpreqMinInterval;
u16 dot11MeshHWMPnetDiameterTraversalTime;
u8 dot11MeshHWMPRootMode;
+ u16 dot11MeshHWMPRannInterval;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c1fa577..9995c83 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1137,6 +1137,10 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
ieee80211_mesh_root_setup(ifmsh);
}
+ if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
+ conf->dot11MeshHWMPRannInterval =
+ nconf->dot11MeshHWMPRannInterval;
+ }
return 0;
}

diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 75ece3d..bac9443 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -372,6 +372,8 @@ IEEE80211_IF_FILE(min_discovery_timeout,
u.mesh.mshcfg.min_discovery_timeout, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
+ u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
#endif


@@ -486,6 +488,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(path_refresh_time);
MESHPARAMS_ADD(min_discovery_timeout);
MESHPARAMS_ADD(dot11MeshHWMPRootMode);
+ MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
#undef MESHPARAMS_ADD
}
#endif
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index e120fef..1c4f53c 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -537,7 +537,8 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)

mesh_path_tx_root_frame(sdata);
mod_timer(&ifmsh->mesh_path_root_timer,
- round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL));
+ round_jiffies(jiffies +
+ usecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPRannInterval * 1024)));
}

#ifdef CONFIG_PM
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 9d9116e..2027207 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -175,7 +175,6 @@ struct mesh_rmc {

#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
-#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ)

#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index d14dfe4..d6dd460 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -694,7 +694,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
u8 ttl, flags, hopcount;
u8 *orig_addr;
u32 orig_sn, metric;
- u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
+ u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
bool root_is_gate;

ttl = rann->rann_ttl;
@@ -742,7 +742,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
cpu_to_le32(orig_sn),
0, NULL, 0, broadcast_addr,
- hopcount, ttl, interval,
+ hopcount, ttl, cpu_to_le32(interval),
cpu_to_le32(metric + mpath->metric),
0, sdata);
mpath->sn = orig_sn;
@@ -1043,11 +1043,11 @@ void
mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
+ u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;

mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
cpu_to_le32(++ifmsh->sn),
0, NULL, 0, broadcast_addr,
0, sdata->u.mesh.mshcfg.element_ttl,
- interval, 0, 0, sdata);
+ cpu_to_le32(interval), 0, 0, sdata);
}
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 5c11608..b5a39d4 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -12,6 +12,7 @@
#define MESH_HOLD_T 100

#define MESH_PATH_TIMEOUT 5000
+#define MESH_RANN_INTERVAL 5000

/*
* Minimum interval between two consecutive PREQs originated by the same
@@ -49,6 +50,7 @@ const struct mesh_config default_mesh_config = {
.dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
.path_refresh_time = MESH_PATH_REFRESH_TIME,
.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
+ .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
};

const struct mesh_setup default_mesh_setup = {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c7b5e44..40cab48 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2955,6 +2955,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
cur_params.dot11MeshHWMPnetDiameterTraversalTime);
NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
cur_params.dot11MeshHWMPRootMode);
+ NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ cur_params.dot11MeshHWMPRannInterval);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -2983,6 +2985,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
};

static const struct nla_policy
@@ -3061,6 +3064,10 @@ do {\
dot11MeshHWMPRootMode, mask,
NL80211_MESHCONF_HWMP_ROOTMODE,
nla_get_u8);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+ dot11MeshHWMPRannInterval, mask,
+ NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ nla_get_u16);
if (mask_out)
*mask_out = mask;

--
1.7.6


2011-08-12 18:12:10

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH v2 1/8] mac80211: improve mpath debugging

On Fri, Aug 12, 2011 at 5:28 AM, Johannes Berg
<[email protected]> wrote:
> On Thu, 2011-08-11 at 19:53 -0700, Thomas Pedersen wrote:
>
>> +#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
>> +static inline void mpath_dbg(const char *fmt, ...)
>> +{
>> + ? ? struct va_format vaf;
>> + ? ? va_list args;
>> +
>> + ? ? va_start(args, fmt);
>> +
>> + ? ? vaf.fmt = fmt;
>> + ? ? vaf.va = &args;
>> +
>> + ? ? printk(KERN_DEBUG "%pV", &vaf);
>> + ? ? va_end(args);
>> + ? ? return;
>> +}
>> +#else
>> +static inline void mpath_dbg(const char *fmt, ...)
>> +{
>> + ? ? return;
>> +}
>> +#endif
>
> Oh, maybe that's too complicated after all... How about
>
> #ifdef ...
> #define ...
> #else
> static inline void mpath_dbg(const char *fmt, ...)
> ? ? ? ?__attribute__ ((format (printf, 1, 2)))
> {
> }
> #endif
>
> Definitely want the format attribute, that was my whole point :)

Oh I see. Looking at it again, my function above doesn't even have any
argument checking :P. Didn't know about that __attribute__ etiher,
thanks!

> Bah, maybe it all doesn't matter, in which case maybe the first version
> is better.

Sure, let's go with the first one.
>
> johannes
>
>

2011-08-12 09:31:26

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 8/8] {nl,cfg,mac}80211: let userspace make meshif mesh gate

On Wed, 2011-08-10 at 14:31 -0700, Thomas Pedersen wrote:
> On Wed, Aug 10, 2011 at 6:47 AM, Johannes Berg
> <[email protected]> wrote:
> > On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:
> >> From: Javier Cardona <[email protected]>
> >>
> >> Allow userspace to set NL80211_MESHCONF_GATE_ANNOUNCEMENTS attribute,
> >> which will advertise this mesh node as being a mesh gate.
> >> NL80211_HWMP_ROOTMODE must be set or this will do nothing.
> >
> > IMHO it should be rejected instead of doing nothing.
> >
> Maybe the "right thing" to do is not require the user to know anything
> about the limitations of our implementation, and instead just enable
> root mode as needed?

I don't know? Is it a limitation of the implementation? I know
practically nothing about mesh :-) It just didn't seem right to silently
ignore something.

johannes


2011-08-12 02:54:26

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 7/8] {nl,cfg,mac}80211: let userspace set RANN interval

From: Javier Cardona <[email protected]>

Allow userspace to set Root Announcement Interval for our mesh
interface. Also, RANN interval is now in proper units of TUs.

Signed-off-by: Javier Cardona <[email protected]>
---
v2:
- use TU_TO_EXP_TIME macrot (Johannes)
include/linux/nl80211.h | 4 ++++
include/net/cfg80211.h | 1 +
net/mac80211/cfg.c | 4 ++++
net/mac80211/debugfs_netdev.c | 3 +++
net/mac80211/mesh.c | 3 ++-
net/mac80211/mesh.h | 1 -
net/mac80211/mesh_hwmp.c | 8 ++++----
net/wireless/mesh.c | 2 ++
net/wireless/nl80211.c | 7 +++++++
9 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 8ad70dc..63ad64b 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1833,6 +1833,9 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
* source mesh point for path selection elements.
*
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between
+ * root announcements are transmitted.
+ *
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -1854,6 +1857,7 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
NL80211_MESHCONF_HWMP_ROOTMODE,
NL80211_MESHCONF_ELEMENT_TTL,
+ NL80211_MESHCONF_HWMP_RANN_INTERVAL,

/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 779e300..de101d9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -691,6 +691,7 @@ struct mesh_config {
u16 dot11MeshHWMPpreqMinInterval;
u16 dot11MeshHWMPnetDiameterTraversalTime;
u8 dot11MeshHWMPRootMode;
+ u16 dot11MeshHWMPRannInterval;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c1fa577..9995c83 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1137,6 +1137,10 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
ieee80211_mesh_root_setup(ifmsh);
}
+ if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
+ conf->dot11MeshHWMPRannInterval =
+ nconf->dot11MeshHWMPRannInterval;
+ }
return 0;
}

diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 75ece3d..bac9443 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -372,6 +372,8 @@ IEEE80211_IF_FILE(min_discovery_timeout,
u.mesh.mshcfg.min_discovery_timeout, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
+IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
+ u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
#endif


@@ -486,6 +488,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(path_refresh_time);
MESHPARAMS_ADD(min_discovery_timeout);
MESHPARAMS_ADD(dot11MeshHWMPRootMode);
+ MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
#undef MESHPARAMS_ADD
}
#endif
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index e120fef..28ab510 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -537,7 +537,8 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)

mesh_path_tx_root_frame(sdata);
mod_timer(&ifmsh->mesh_path_root_timer,
- round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL));
+ round_jiffies(TU_TO_EXP_TIME(
+ ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
}

#ifdef CONFIG_PM
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 9d9116e..2027207 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -175,7 +175,6 @@ struct mesh_rmc {

#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
-#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ)

#define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 7b517c4..ae3de75 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -695,7 +695,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
u8 ttl, flags, hopcount;
u8 *orig_addr;
u32 orig_sn, metric;
- u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
+ u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
bool root_is_gate;

ttl = rann->rann_ttl;
@@ -743,7 +743,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
cpu_to_le32(orig_sn),
0, NULL, 0, broadcast_addr,
- hopcount, ttl, interval,
+ hopcount, ttl, cpu_to_le32(interval),
cpu_to_le32(metric + mpath->metric),
0, sdata);
mpath->sn = orig_sn;
@@ -1044,11 +1044,11 @@ void
mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- u32 interval = cpu_to_le32(IEEE80211_MESH_RANN_INTERVAL);
+ u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;

mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
cpu_to_le32(++ifmsh->sn),
0, NULL, 0, broadcast_addr,
0, sdata->u.mesh.mshcfg.element_ttl,
- interval, 0, 0, sdata);
+ cpu_to_le32(interval), 0, 0, sdata);
}
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 5c11608..b5a39d4 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -12,6 +12,7 @@
#define MESH_HOLD_T 100

#define MESH_PATH_TIMEOUT 5000
+#define MESH_RANN_INTERVAL 5000

/*
* Minimum interval between two consecutive PREQs originated by the same
@@ -49,6 +50,7 @@ const struct mesh_config default_mesh_config = {
.dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
.path_refresh_time = MESH_PATH_REFRESH_TIME,
.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
+ .dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
};

const struct mesh_setup default_mesh_setup = {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index cd5994f..d39a5a1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2958,6 +2958,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
cur_params.dot11MeshHWMPnetDiameterTraversalTime);
NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
cur_params.dot11MeshHWMPRootMode);
+ NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ cur_params.dot11MeshHWMPRannInterval);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -2986,6 +2988,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
+ [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
};

static const struct nla_policy
@@ -3064,6 +3067,10 @@ do {\
dot11MeshHWMPRootMode, mask,
NL80211_MESHCONF_HWMP_ROOTMODE,
nla_get_u8);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+ dot11MeshHWMPRannInterval, mask,
+ NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ nla_get_u16);
if (mask_out)
*mask_out = mask;

--
1.7.4.1


2011-08-09 23:46:35

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 8/8] {nl,cfg,mac}80211: let userspace make meshif mesh gate

From: Javier Cardona <[email protected]>

Allow userspace to set NL80211_MESHCONF_GATE_ANNOUNCEMENTS attribute,
which will advertise this mesh node as being a mesh gate.
NL80211_HWMP_ROOTMODE must be set or this will do nothing.

Signed-off-by: Javier Cardona <[email protected]>
---
include/linux/nl80211.h | 5 +++++
include/net/cfg80211.h | 5 +++++
net/mac80211/cfg.c | 4 ++++
net/mac80211/debugfs_netdev.c | 3 +++
net/mac80211/mesh_hwmp.c | 5 ++++-
net/wireless/mesh.c | 1 +
net/wireless/nl80211.c | 7 +++++++
7 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 63ad64b..af2d768 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1836,6 +1836,10 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between
* root announcements are transmitted.
*
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ * access to a broader network beyond the MBSS. This is done via Root
+ * Announcement frames.
+ *
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -1858,6 +1862,7 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_HWMP_ROOTMODE,
NL80211_MESHCONF_ELEMENT_TTL,
NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ NL80211_MESHCONF_GATE_ANNOUNCEMENTS,

/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 207e508..7254157 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -684,6 +684,11 @@ struct mesh_config {
u16 dot11MeshHWMPnetDiameterTraversalTime;
u8 dot11MeshHWMPRootMode;
u16 dot11MeshHWMPRannInterval;
+ /* This is missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol
+ * set to true only means that the station will announce others it's a
+ * mesh gate, but not necessarily using the gate announcement protocol.
+ * Still keeping the same nomenclature to be in sync with the spec. */
+ bool dot11MeshGateAnnouncementProtocol;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 9995c83..7d17a91 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1137,6 +1137,10 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
ieee80211_mesh_root_setup(ifmsh);
}
+ if (_chg_mesh_attr(NL80211_MESHCONF_GATE_ANNOUNCEMENTS, mask)) {
+ conf->dot11MeshGateAnnouncementProtocol =
+ nconf->dot11MeshGateAnnouncementProtocol;
+ }
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
conf->dot11MeshHWMPRannInterval =
nconf->dot11MeshHWMPRannInterval;
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index bac9443..6e8eab7 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -372,6 +372,8 @@ IEEE80211_IF_FILE(min_discovery_timeout,
u.mesh.mshcfg.min_discovery_timeout, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
+IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
+ u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
#endif
@@ -489,6 +491,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(min_discovery_timeout);
MESHPARAMS_ADD(dot11MeshHWMPRootMode);
MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
+ MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
#undef MESHPARAMS_ADD
}
#endif
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index d6dd460..ec920dd 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -1044,8 +1044,11 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+ u8 flags;

- mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
+ flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
+ ? RANN_FLAG_IS_GATE : 0;
+ mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
cpu_to_le32(++ifmsh->sn),
0, NULL, 0, broadcast_addr,
0, sdata->u.mesh.mshcfg.element_ttl,
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index b5a39d4..4423e64 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -51,6 +51,7 @@ const struct mesh_config default_mesh_config = {
.path_refresh_time = MESH_PATH_REFRESH_TIME,
.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
.dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
+ .dot11MeshGateAnnouncementProtocol = false,
};

const struct mesh_setup default_mesh_setup = {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 40cab48..59f6c31 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2957,6 +2957,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
cur_params.dot11MeshHWMPRootMode);
NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
cur_params.dot11MeshHWMPRannInterval);
+ NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ cur_params.dot11MeshGateAnnouncementProtocol);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -2986,6 +2988,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
[NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
};

static const struct nla_policy
@@ -3068,6 +3071,10 @@ do {\
dot11MeshHWMPRannInterval, mask,
NL80211_MESHCONF_HWMP_RANN_INTERVAL,
nla_get_u16);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+ dot11MeshGateAnnouncementProtocol, mask,
+ NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ nla_get_u8);
if (mask_out)
*mask_out = mask;

--
1.7.6


2011-08-10 13:38:30

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/8] mac80211: improve mpath debugging

On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:

> +#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

Maybe this should be a static inline for checking the fmt args even when
it's compiled out?

johannes


2011-08-09 23:46:27

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 3/8] mac80211: mesh locking fixes

From: Javier Cardona <[email protected]>

mesh_queue_preq is invoked invoked from both user (work queue) and
softirq (timer) context, so the _bh version of spinlock needs to be
used. Also, the mpath->state_lock should be softirq safe as well.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 89f469b..b4480a9 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -654,12 +654,12 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
mpath = node->mpath;
if (mpath->sdata == sdata &&
memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
- spin_lock(&mpath->state_lock);
+ spin_lock_bh(&mpath->state_lock);
mpath->flags |= MESH_PATH_RESOLVING;
hlist_del_rcu(&node->list);
call_rcu(&node->rcu, mesh_path_node_reclaim);
atomic_dec(&tbl->entries);
- spin_unlock(&mpath->state_lock);
+ spin_unlock_bh(&mpath->state_lock);
goto enddel;
}
}
--
1.7.6


2011-08-22 21:57:18

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH v2 1/8] mac80211: improve mpath debugging

On Mon, Aug 22, 2011 at 11:34 AM, John W. Linville
<[email protected]> wrote:
> On Fri, Aug 12, 2011 at 11:12:08AM -0700, Thomas Pedersen wrote:
>> On Fri, Aug 12, 2011 at 5:28 AM, Johannes Berg
>> <[email protected]> wrote:
>
>> > Definitely want the format attribute, that was my whole point :)
>>
>> Oh I see. Looking at it again, my function above doesn't even have any
>> argument checking :P. Didn't know about that __attribute__ etiher,
>> thanks!
>>
>> > Bah, maybe it all doesn't matter, in which case maybe the first version
>> > is better.
>>
>> Sure, let's go with the first one.
>
> OK, I'm confused -- do we want to merge the versions posted on
> 9 August? ?Or the ones from 11 August? ?Or...?
>

I was referring to the patch from 9 August (v1).

Thomas
> John
> --
> John W. Linville ? ? ? ? ? ? ? ?Someday the world will need a hero, and you
> [email protected] ? ? ? ? ? ? ? ? ?might be all we have. ?Be ready.
>

2011-08-10 20:14:37

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/8] mac80211: improve mpath debugging

On Wed, 2011-08-10 at 13:11 -0700, Thomas Pedersen wrote:
> On Wed, Aug 10, 2011 at 6:38 AM, Johannes Berg
> <[email protected]> wrote:
> > On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:
> >
> >> +#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
> >
> > Maybe this should be a static inline for checking the fmt args even when
> > it's compiled out?
> >
> I don't really see the point, since all this would give us is the
> compiler checking whether a const char * was passed as an argument to
> fmt, right?

No, if you annotate it correctly gcc will also check that the arguments
match, and warn if you do

mpath_dbg("foo: %s", 7)

for example :-)

johannes


2011-08-12 12:28:24

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 1/8] mac80211: improve mpath debugging

On Thu, 2011-08-11 at 19:53 -0700, Thomas Pedersen wrote:

> +#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG
> +static inline void mpath_dbg(const char *fmt, ...)
> +{
> + struct va_format vaf;
> + va_list args;
> +
> + va_start(args, fmt);
> +
> + vaf.fmt = fmt;
> + vaf.va = &args;
> +
> + printk(KERN_DEBUG "%pV", &vaf);
> + va_end(args);
> + return;
> +}
> +#else
> +static inline void mpath_dbg(const char *fmt, ...)
> +{
> + return;
> +}
> +#endif

Oh, maybe that's too complicated after all... How about

#ifdef ...
#define ...
#else
static inline void mpath_dbg(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)))
{
}
#endif

Definitely want the format attribute, that was my whole point :)

Bah, maybe it all doesn't matter, in which case maybe the first version
is better.

johannes


2011-08-09 23:46:25

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 1/8] mac80211: improve mpath debugging

From: Javier Cardona <[email protected]>

make hwmp_dbg print the relevant sdata->name by default and improve
formatting. Also add mpath_dbg macro for debugging of mesh path
operations.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/Kconfig | 13 +++++++++++++
net/mac80211/mesh_hwmp.c | 23 ++++++++++++-----------
net/mac80211/mesh_pathtbl.c | 6 ++++++
3 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index f5fdfcb..d1886b5 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -199,6 +199,19 @@ config MAC80211_VERBOSE_MPL_DEBUG

Do not select this option.

+config MAC80211_VERBOSE_MPATH_DEBUG
+ bool "Verbose mesh path debugging"
+ depends on MAC80211_DEBUG_MENU
+ depends on MAC80211_MESH
+ ---help---
+ Selecting this option causes mac80211 to print out very
+ verbose mesh path selection debugging messages (when mac80211
+ is taking part in a mesh network).
+ It should not be selected on production systems as those
+ messages are remotely triggerable.
+
+ Do not select this option.
+
config MAC80211_VERBOSE_MHWMP_DEBUG
bool "Verbose mesh HWMP routing debugging"
depends on MAC80211_DEBUG_MENU
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 2e528b0..14803ae 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -11,7 +11,8 @@
#include "mesh.h"

#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG
-#define mhwmp_dbg(fmt, args...) printk(KERN_DEBUG "Mesh HWMP: " fmt, ##args)
+#define mhwmp_dbg(fmt, args...) \
+ printk(KERN_DEBUG "Mesh HWMP (%s): " fmt "\n", sdata->name, ##args)
#else
#define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
@@ -137,19 +138,19 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,

switch (action) {
case MPATH_PREQ:
- mhwmp_dbg("sending PREQ to %pM\n", target);
+ mhwmp_dbg("sending PREQ to %pM", target);
ie_len = 37;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PREQ;
break;
case MPATH_PREP:
- mhwmp_dbg("sending PREP to %pM\n", target);
+ mhwmp_dbg("sending PREP to %pM", target);
ie_len = 31;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PREP;
break;
case MPATH_RANN:
- mhwmp_dbg("sending RANN from %pM\n", orig_addr);
+ mhwmp_dbg("sending RANN from %pM", orig_addr);
ie_len = sizeof(struct ieee80211_rann_ie);
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_RANN;
@@ -493,10 +494,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
orig_sn = PREQ_IE_ORIG_SN(preq_elem);
target_flags = PREQ_IE_TARGET_F(preq_elem);

- mhwmp_dbg("received PREQ from %pM\n", orig_addr);
+ mhwmp_dbg("received PREQ from %pM", orig_addr);

if (memcmp(target_addr, sdata->vif.addr, ETH_ALEN) == 0) {
- mhwmp_dbg("PREQ is for us\n");
+ mhwmp_dbg("PREQ is for us");
forward = false;
reply = true;
metric = 0;
@@ -532,7 +533,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
lifetime = PREQ_IE_LIFETIME(preq_elem);
ttl = ifmsh->mshcfg.element_ttl;
if (ttl != 0) {
- mhwmp_dbg("replying to the PREQ\n");
+ mhwmp_dbg("replying to the PREQ");
mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr,
cpu_to_le32(target_sn), 0, orig_addr,
cpu_to_le32(orig_sn), mgmt->sa, 0, ttl,
@@ -552,7 +553,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
ifmsh->mshstats.dropped_frames_ttl++;
return;
}
- mhwmp_dbg("forwarding the PREQ from %pM\n", orig_addr);
+ mhwmp_dbg("forwarding the PREQ from %pM", orig_addr);
--ttl;
flags = PREQ_IE_FLAGS(preq_elem);
preq_id = PREQ_IE_PREQ_ID(preq_elem);
@@ -587,7 +588,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
u8 next_hop[ETH_ALEN];
u32 target_sn, orig_sn, lifetime;

- mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem));
+ mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));

/* Note that we divert from the draft nomenclature and denominate
* destination to what the draft refers to as origininator. So in this
@@ -798,7 +799,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)

preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
if (!preq_node) {
- mhwmp_dbg("could not allocate PREQ node\n");
+ mhwmp_dbg("could not allocate PREQ node");
return;
}

@@ -807,7 +808,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
kfree(preq_node);
if (printk_ratelimit())
- mhwmp_dbg("PREQ node queue full\n");
+ mhwmp_dbg("PREQ node queue full");
return;
}

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 3ef6ad4..819d8e4 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -17,6 +17,12 @@
#include "ieee80211_i.h"
#include "mesh.h"

+#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
+
/* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
#define INIT_PATHS_SIZE_ORDER 2

--
1.7.6


2011-08-10 20:40:55

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH 1/8] mac80211: improve mpath debugging

On Wed, Aug 10, 2011 at 1:14 PM, Johannes Berg
<[email protected]> wrote:
> On Wed, 2011-08-10 at 13:11 -0700, Thomas Pedersen wrote:
>> On Wed, Aug 10, 2011 at 6:38 AM, Johannes Berg
>> <[email protected]> wrote:
>> > On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:
>> >
>> >> +#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
>> >
>> > Maybe this should be a static inline for checking the fmt args even when
>> > it's compiled out?
>> >
>> I don't really see the point, since all this would give us is the
>> compiler checking whether a const char * was passed as an argument to
>> fmt, right?
>
> No, if you annotate it correctly gcc will also check that the arguments
> match, and warn if you do
>
> mpath_dbg("foo: %s", 7)
>
> for example :-)

Ah, well OK. The next version will include this change.

Thomas

2011-08-12 02:54:29

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 8/8] {nl,cfg,mac}80211: let userspace make meshif mesh gate

From: Javier Cardona <[email protected]>

Allow userspace to set NL80211_MESHCONF_GATE_ANNOUNCEMENTS attribute,
which will advertise this mesh node as being a mesh gate.
dot11MeshHWMPRootMode must be set as root announcements are used to
indicate we're a mesh gate. Set this if user forgot for now.

Signed-off-by: Javier Cardona <[email protected]>
Signed-off-by: Thomas Pedersen <[email protected]>
---
include/linux/nl80211.h | 5 +++++
include/net/cfg80211.h | 5 +++++
net/mac80211/cfg.c | 12 ++++++++++++
net/mac80211/debugfs_netdev.c | 3 +++
net/mac80211/mesh_hwmp.c | 5 ++++-
net/wireless/mesh.c | 1 +
net/wireless/nl80211.c | 7 +++++++
7 files changed, 37 insertions(+), 1 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 63ad64b..af2d768 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1836,6 +1836,10 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between
* root announcements are transmitted.
*
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ * access to a broader network beyond the MBSS. This is done via Root
+ * Announcement frames.
+ *
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -1858,6 +1862,7 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_HWMP_ROOTMODE,
NL80211_MESHCONF_ELEMENT_TTL,
NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+ NL80211_MESHCONF_GATE_ANNOUNCEMENTS,

/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index de101d9..b2e01ca 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -692,6 +692,11 @@ struct mesh_config {
u16 dot11MeshHWMPnetDiameterTraversalTime;
u8 dot11MeshHWMPRootMode;
u16 dot11MeshHWMPRannInterval;
+ /* This is missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol
+ * set to true only means that the station will announce others it's a
+ * mesh gate, but not necessarily using the gate announcement protocol.
+ * Still keeping the same nomenclature to be in sync with the spec. */
+ bool dot11MeshGateAnnouncementProtocol;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 9995c83..6ab67ab 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1137,6 +1137,18 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode;
ieee80211_mesh_root_setup(ifmsh);
}
+ if (_chg_mesh_attr(NL80211_MESHCONF_GATE_ANNOUNCEMENTS, mask)) {
+ /* our current gate announcement implementation rides on root
+ * announcements, so require this ifmsh to also be a root node
+ * */
+ if (nconf->dot11MeshGateAnnouncementProtocol &&
+ !conf->dot11MeshHWMPRootMode) {
+ conf->dot11MeshHWMPRootMode = 1;
+ ieee80211_mesh_root_setup(ifmsh);
+ }
+ conf->dot11MeshGateAnnouncementProtocol =
+ nconf->dot11MeshGateAnnouncementProtocol;
+ }
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) {
conf->dot11MeshHWMPRannInterval =
nconf->dot11MeshHWMPRannInterval;
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index bac9443..6e8eab7 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -372,6 +372,8 @@ IEEE80211_IF_FILE(min_discovery_timeout,
u.mesh.mshcfg.min_discovery_timeout, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPRootMode,
u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC);
+IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol,
+ u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC);
IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
#endif
@@ -489,6 +491,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(min_discovery_timeout);
MESHPARAMS_ADD(dot11MeshHWMPRootMode);
MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
+ MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
#undef MESHPARAMS_ADD
}
#endif
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index ae3de75..fd4f76a 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -1045,8 +1045,11 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval;
+ u8 flags;

- mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
+ flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol)
+ ? RANN_FLAG_IS_GATE : 0;
+ mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
cpu_to_le32(++ifmsh->sn),
0, NULL, 0, broadcast_addr,
0, sdata->u.mesh.mshcfg.element_ttl,
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index b5a39d4..4423e64 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -51,6 +51,7 @@ const struct mesh_config default_mesh_config = {
.path_refresh_time = MESH_PATH_REFRESH_TIME,
.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
.dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
+ .dot11MeshGateAnnouncementProtocol = false,
};

const struct mesh_setup default_mesh_setup = {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d39a5a1..2ce7ffa 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2960,6 +2960,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
cur_params.dot11MeshHWMPRootMode);
NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_RANN_INTERVAL,
cur_params.dot11MeshHWMPRannInterval);
+ NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ cur_params.dot11MeshGateAnnouncementProtocol);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -2989,6 +2991,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
[NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
[NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
};

static const struct nla_policy
@@ -3071,6 +3074,10 @@ do {\
dot11MeshHWMPRannInterval, mask,
NL80211_MESHCONF_HWMP_RANN_INTERVAL,
nla_get_u16);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+ dot11MeshGateAnnouncementProtocol, mask,
+ NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ nla_get_u8);
if (mask_out)
*mask_out = mask;

--
1.7.4.1


2011-08-09 23:46:26

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 2/8] mac80211: fix mpath timer NULL function

From: Javier Cardona <[email protected]>

If we have an mpath whose timer has not been initialized, don't try to
delete it.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 819d8e4..89f469b 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -619,7 +619,8 @@ 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);
+ if (node->mpath->timer.function)
+ del_timer_sync(&node->mpath->timer);
atomic_dec(&sdata->u.mesh.mpaths);
kfree(node->mpath);
kfree(node);
@@ -768,7 +769,8 @@ static void mesh_path_node_free(struct hlist_node *p, bool free_leafs)
mpath = node->mpath;
hlist_del_rcu(p);
if (free_leafs) {
- del_timer_sync(&mpath->timer);
+ if (mpath->timer.function)
+ del_timer_sync(&mpath->timer);
kfree(mpath);
}
kfree(node);
--
1.7.6


2011-08-10 13:39:22

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/8] mac80211: fix mpath timer NULL function

On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:
> From: Javier Cardona <[email protected]>
>
> If we have an mpath whose timer has not been initialized, don't try to
> delete it.

IMHO this doesn't make sense -- always initialising the timer but not
adding it when not necessary seems better?

johannes


2011-08-10 21:31:18

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH 8/8] {nl,cfg,mac}80211: let userspace make meshif mesh gate

On Wed, Aug 10, 2011 at 6:47 AM, Johannes Berg
<[email protected]> wrote:
> On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:
>> From: Javier Cardona <[email protected]>
>>
>> Allow userspace to set NL80211_MESHCONF_GATE_ANNOUNCEMENTS attribute,
>> which will advertise this mesh node as being a mesh gate.
>> NL80211_HWMP_ROOTMODE must be set or this will do nothing.
>
> IMHO it should be rejected instead of doing nothing.
>
Maybe the "right thing" to do is not require the user to know anything
about the limitations of our implementation, and instead just enable
root mode as needed?
> johannes
>
>

2011-08-12 02:54:18

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH v2 3/8] mac80211: mesh locking fixes

From: Javier Cardona <[email protected]>

mesh_queue_preq is invoked invoked from both user (work queue) and
softirq (timer) context, so the _bh version of spinlock needs to be
used. Also, the mpath->state_lock should be softirq safe as well.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 7d050af..0d80d7d 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -670,12 +670,12 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
mpath = node->mpath;
if (mpath->sdata == sdata &&
memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
- spin_lock(&mpath->state_lock);
+ spin_lock_bh(&mpath->state_lock);
mpath->flags |= MESH_PATH_RESOLVING;
hlist_del_rcu(&node->list);
call_rcu(&node->rcu, mesh_path_node_reclaim);
atomic_dec(&tbl->entries);
- spin_unlock(&mpath->state_lock);
+ spin_unlock_bh(&mpath->state_lock);
goto enddel;
}
}
--
1.7.4.1


2011-08-10 13:47:14

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 7/8] {nl,cfg,mac}80211: let userspace set RANN interval

On Tue, 2011-08-09 at 16:45 -0700, Thomas Pedersen wrote:

> mod_timer(&ifmsh->mesh_path_root_timer,
> - round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL));
> + round_jiffies(jiffies +
> + usecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPRannInterval * 1024)));

TU_TO_EXP_TIME ?

johannes


2011-08-09 23:46:28

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 4/8] mac80211: fix mesh path flushing

From: Javier Cardona <[email protected]>

Previously, mpaths were never flushed since the mpath is not active once
we call this function.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index b4480a9..de8c4f6 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -735,8 +735,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath)
{
struct sk_buff *skb;

- while ((skb = skb_dequeue(&mpath->frame_queue)) &&
- (mpath->flags & MESH_PATH_ACTIVE))
+ while ((skb = skb_dequeue(&mpath->frame_queue)) != NULL)
mesh_path_discard_frame(skb, mpath->sdata);
}

--
1.7.6