2013-05-03 02:36:09

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 00/12] MBSS sharing across multiple interfaces

This patchset enables multiple interfaces on the same host to share mesh path
selection and frame forwarding duties. The peering state machine remains
per-interface.

The user interface looks something like:

iw wlan0 mesh join foo shared on
iw wlan1 mesh join foo shared on

As long as wlan0 and wlan1 have a matching mesh setup profile, they will be
considered part of the same MBSS.

This approach is superior to simple 802.1d briding, since mac80211 can
dynamically pick the better link instead of simply disabling an entire port.
The added link knowledge also enables bonding and alternation in the future.

Bob Copeland (6):
mac80211: track and share mesh BSSes among interfaces
mac80211: mesh: add function to tx on all other mbss ifaces
mac80211: use all MBSS interfaces for path selection
mac80211: forward group frames on mbss-shared interfaces
mac80211: add shared-mbss transmit path
mac08211: add shared-mbss receive path handling

Thomas Pedersen (6):
mac80211: assign outgoing interface with nexthop
mac80211: forward frames on correct mbss-shared interface
mac80211: notify bridge when leaving mesh
mac80211: make RMC per-mbss
{nl,mac}80211: specify MBSS sharing on/off
{nl,mac}80211: allow mpath dump to span local MBSS

include/net/cfg80211.h | 8 +-
include/uapi/linux/nl80211.h | 12 +-
net/mac80211/cfg.c | 17 +--
net/mac80211/ieee80211_i.h | 37 +++++-
net/mac80211/iface.c | 3 -
net/mac80211/mesh.c | 276 +++++++++++++++++++++++++++++++++++++++---
net/mac80211/mesh.h | 24 ++--
net/mac80211/mesh_hwmp.c | 133 ++++++++++++++------
net/mac80211/mesh_pathtbl.c | 68 +++++++----
net/mac80211/rx.c | 110 +++++++++++++----
net/mac80211/tx.c | 8 +-
net/wireless/mesh.c | 1 +
net/wireless/nl80211.c | 21 +++-
net/wireless/rdev-ops.h | 10 +-
14 files changed, 599 insertions(+), 129 deletions(-)

--
1.7.10.4



2013-05-07 14:09:50

by Bob Copeland

[permalink] [raw]
Subject: Re: [RFC 01/12] mac80211: track and share mesh BSSes among interfaces

On Tue, May 07, 2013 at 03:37:42PM +0200, Johannes Berg wrote:
> Ok this is big ... Let me tackle it patch by patch I guess :-)
>
> > +struct mesh_local_bss {
>
> > + bool can_share;
>
> Does that even make sense? I mean, wouldn't you simply not link/create
> such an entry if the given vif can't share?

We could do that, but as written mpath table now wants an mbss pointer
in either case. Seemed more straight-forward to just always require
it even though the structures are kind of pointless for unshared vifs.

> > @@ -818,6 +986,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
> > local->fif_other_bss--;
> > atomic_dec(&local->iff_allmultis);
> > ieee80211_configure_filter(local);
> > +
> > + netif_tx_stop_all_queues(sdata->dev);
>
> how is that related to this patch?

Intent was to be sure pending queue doesn't run while we're taking
out this interface (since another interface may be queueing frames
here), but that can't actually happen until a later patch. So
maybe it should be split out or moved later.

The stop path should be revisited anyway, there's some duplication
in what ieee80211_do_stop() does and this, which is really about when
stop_mesh() gets called and when mbss gets freed.

--
Bob Copeland %% http://www.bobcopeland.com

2013-05-03 02:36:32

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 10/12] mac08211: add shared-mbss receive path handling

From: Bob Copeland <[email protected]>

If a destination interface is participating in a shared mbss, then
receive data frames on the correct interface (or all for mcast) when
passing frames to upper layers.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/rx.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 52 insertions(+), 4 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 850bfe3..f705210 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -594,19 +594,22 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
- char *dev_addr = rx->sdata->vif.addr;
+ struct mesh_local_bss *mbss = mbss(rx->sdata);
+
+ if (!mbss)
+ return RX_DROP_MONITOR;

if (ieee80211_is_data(hdr->frame_control)) {
if (is_multicast_ether_addr(hdr->addr1)) {
if (ieee80211_has_tods(hdr->frame_control) ||
!ieee80211_has_fromds(hdr->frame_control))
return RX_DROP_MONITOR;
- if (ether_addr_equal(hdr->addr3, dev_addr))
+ if (mesh_bss_matches_addr(mbss, hdr->addr3))
return RX_DROP_MONITOR;
} else {
if (!ieee80211_has_a4(hdr->frame_control))
return RX_DROP_MONITOR;
- if (ether_addr_equal(hdr->addr4, dev_addr))
+ if (mesh_bss_matches_addr(mbss, hdr->addr4))
return RX_DROP_MONITOR;
}
}
@@ -2074,7 +2077,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)

/* Frame has reached destination. Don't forward */
if (!is_multicast_ether_addr(hdr->addr1) &&
- ether_addr_equal(sdata->vif.addr, hdr->addr3))
+ mesh_bss_matches_addr(mbss, hdr->addr3))
return RX_CONTINUE;

if (!--mesh_hdr->ttl) {
@@ -2157,6 +2160,7 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_sub_if_data *tmp_sdata;
struct ieee80211_local *local = rx->local;
struct net_device *dev = sdata->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@@ -2183,6 +2187,19 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
}

+ if (ieee80211_vif_is_mesh(&rx->sdata->vif) &&
+ !is_multicast_ether_addr(hdr->addr1)) {
+ u8 *dest = ieee80211_get_DA(hdr);
+
+ /* deliver unicast frames to the dest netif */
+ tmp_sdata = mesh_bss_find_if(mbss(sdata), dest);
+ if (tmp_sdata && tmp_sdata != sdata) {
+ local = tmp_sdata->local;
+ rx->sdata = tmp_sdata;
+ dev = tmp_sdata->dev;
+ }
+ }
+
err = __ieee80211_data_to_8023(rx, &port_control);
if (unlikely(err))
return RX_DROP_UNUSABLE;
@@ -2198,6 +2215,37 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
rx->sdata = sdata;
}

+ if (ieee80211_vif_is_mesh(&rx->sdata->vif)) {
+ struct mesh_local_bss *mbss = mbss(sdata);
+ struct sk_buff *skb = rx->skb, *fwd_skb;
+ u8 *dest = ((struct ethhdr *)rx->skb->data)->h_dest;
+
+ if (is_multicast_ether_addr(dest)) {
+ /* deliver mcast frames to all other interfaces */
+ list_for_each_entry_rcu(tmp_sdata, &mbss->if_list,
+ u.mesh.if_list) {
+
+ if (sdata == tmp_sdata)
+ continue;
+
+ fwd_skb = skb_copy(skb, GFP_ATOMIC);
+ if (!fwd_skb)
+ break;
+
+ dev = tmp_sdata->dev;
+ fwd_skb->dev = dev;
+ rx->skb = fwd_skb;
+ rx->sdata = tmp_sdata;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += rx->skb->len;
+ ieee80211_deliver_skb(rx);
+ }
+ rx->sdata = sdata;
+ rx->skb = skb;
+ dev = sdata->dev;
+ }
+ }
+
rx->skb->dev = dev;

dev->stats.rx_packets++;
--
1.7.10.4


2013-05-03 14:36:15

by Bob Copeland

[permalink] [raw]
Subject: Re: [RFC 00/12] MBSS sharing across multiple interfaces

On Fri, May 03, 2013 at 01:25:34PM +0000, Chaoxing Lin wrote:
> I have some questions and comments.
>
> Question 1
>
> The typical use case of multiple interfaces on this same host is to do
> RF segregation in order to improve overall network performance. e.g.
> divide a original mesh of 16 radios into 2 meshes of 8 radios each.
> This multi-radio host bridges these two small meshes which are on
> different channels. I can't see why user would put multiple radios of
> the same host on the same channel. They would just interfere with each
> other very badly.

Yes, you want to use different channels. Also, you need to have good
spacing between the radios, because even on different channels, closely
located radios will interfere. We found that putting one in 2.4 ghz
band and one in 5 ghz band worked without resorting to directional
antennas or the like.

> In MPP where there are multiple mesh interfaces, AP interface and/or Ethernet interface, how does this "MBSS sharing" work?
> a. add both mesh interface in 802.1d bridge, or
> b. add either interface in bridge, or
> c. sharing can't be used

You should be able to add either interface in the bridge.

--
Bob Copeland %% http://www.bobcopeland.com

2013-05-24 20:32:36

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 06/12] mac80211: notify bridge when leaving mesh

On Tue, 2013-05-21 at 18:09 -0700, Thomas Pedersen wrote:
> Hey, Sorry for the late response.

Me too :)

> >> netif_carrier_off(sdata->dev);
> >> + if (sdata->dev->priv_flags & IFF_BRIDGE_PORT)
> >> + /* stop bridge transmissions */
> >> + call_netdevice_notifiers(NETDEV_CHANGE, sdata->dev);
> >
> > Err, this seems like a really bad hack? I don't really think drivers
> > should call that?
>
> Why not? We're just notifying the bridge interface that this port has
> gone down, to avoid dereferencing a null pointer (on bridge flood
> traffic) after the mesh_bss has been removed.
>
> Is cfg80211_leave_mesh() an acceptable location for this fix?

I'm not really convinced it's an acceptable fix in itself? Why should we
ever have to call netdev notifiers, that seems odd to me. Also why would
that prevent a crash? Wouldn't we just drop packets for the mesh if we
aren't joined in a mesh any more? Or something like that? Accessing the
priv flags and then calling the netdev notifiers seems really strange to
me. If this was necessary, then wouldn't netif_carrier_off() do it
internally?

johannes


2013-05-03 02:36:27

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 08/12] mac80211: forward group frames on mbss-shared interfaces

From: Bob Copeland <[email protected]>

When multiple local interfaces are in the same MBSS, we should
forward group-directed data frames received on one interface
for transmit on the other interfaces, so that the frames may be
seen on other channels.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/rx.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 0c5f870..850bfe3 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2142,6 +2142,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)

IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
ieee80211_add_pending_skb(local, fwd_skb);
+ if (is_multicast_ether_addr(fwd_hdr->addr1))
+ mesh_bss_forward_tx(sdata, fwd_skb);
out:
if (is_multicast_ether_addr(hdr->addr1) ||
sdata->dev->flags & IFF_PROMISC)
--
1.7.10.4


2013-05-07 15:56:38

by Bob Copeland

[permalink] [raw]
Subject: Re: [RFC 01/12] mac80211: track and share mesh BSSes among interfaces

On Tue, May 07, 2013 at 04:22:15PM +0200, Johannes Berg wrote:
> But why even add it to the global list if you only need it locally?

Gotcha - agreed, makes sense to not do so and drop the can_share bit.

--
Bob Copeland %% http://www.bobcopeland.com

2013-05-03 02:36:23

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 06/12] mac80211: notify bridge when leaving mesh

After turning carrier off, any parent bridge interface
needs to be notified. Otherwise we would see a panic when
attempting to transmit frames on a mesh interface which
hadn't yet been put down.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index eac9988..271ddc9 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -993,6 +993,9 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
struct beacon_data *bcn;

netif_carrier_off(sdata->dev);
+ if (sdata->dev->priv_flags & IFF_BRIDGE_PORT)
+ /* stop bridge transmissions */
+ call_netdevice_notifiers(NETDEV_CHANGE, sdata->dev);

/* stop the beacon */
ifmsh->mesh_id_len = 0;
--
1.7.10.4


2013-05-07 14:12:30

by Bob Copeland

[permalink] [raw]
Subject: Re: [RFC 03/12] mac80211: use all MBSS interfaces for path selection

On Tue, May 07, 2013 at 03:40:45PM +0200, Johannes Berg wrote:
> > /**
> > + * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame and
> > + * insert the correct outgoing interface on the skb cb. Calling this function
> > + * is considered "using" the associated mpath, so preempt a path refresh if
> > + * this mpath expires soon.
>
> This is of course completely bogus kernel-doc :)

Ack, thanks.

--
Bob Copeland %% http://www.bobcopeland.com

2013-05-07 13:40:49

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 03/12] mac80211: use all MBSS interfaces for path selection

On Thu, 2013-05-02 at 19:33 -0700, Thomas Pedersen wrote:

> /**
> - * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
> - * this function is considered "using" the associated mpath, so preempt a path
> - * refresh if this mpath expires soon.
> + * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame and
> + * insert the correct outgoing interface on the skb cb. Calling this function
> + * is considered "using" the associated mpath, so preempt a path refresh if
> + * this mpath expires soon.

This is of course completely bogus kernel-doc :)

johannes


2013-05-03 02:36:15

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 03/12] mac80211: use all MBSS interfaces for path selection

From: Bob Copeland <[email protected]>

Change the HWMP path selection code to establish paths using
all interfaces participating in a shared mbss. This means that
group-addressed action frames like PREQ will go out on each
interface, while individually addressed frames use whichever
interface has the destination as a peer.

When processing received frames, consider it a match if any
local interface in the mbss matches the target address.

Finally, mesh_path_lookup() now scans the path table on each
interface until a path (if any) is found so that paths can
be shared among the interfaces.

[ PERR/unicast frame handling fixes from Thomas Pedersen ]

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/cfg.c | 8 +--
net/mac80211/mesh.h | 6 +--
net/mac80211/mesh_hwmp.c | 121 ++++++++++++++++++++++++++++++-------------
net/mac80211/mesh_pathtbl.c | 47 +++++++++++------
net/mac80211/rx.c | 5 +-
net/mac80211/tx.c | 5 +-
6 files changed, 128 insertions(+), 64 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1f51bdf..76e9575 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1605,8 +1605,8 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
return -ENOENT;
}

- mpath = mesh_path_lookup(sdata, dst);
- if (!mpath) {
+ mpath = mesh_path_lookup(mbss(sdata), dst);
+ if (!mpath || mpath->sdata != sdata) {
rcu_read_unlock();
return -ENOENT;
}
@@ -1669,8 +1669,8 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);

rcu_read_lock();
- mpath = mesh_path_lookup(sdata, dst);
- if (!mpath) {
+ mpath = mesh_path_lookup(mbss(sdata), dst);
+ if (!mpath || mpath->sdata != sdata) {
rcu_read_unlock();
return -ENOENT;
}
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 4a1a15e..2f83e8c 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -258,14 +258,14 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
struct ieee802_11_elems *elems);

/* Mesh paths */
-int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
+int mesh_nexthop_lookup(struct mesh_local_bss *mbss,
struct sk_buff *skb);
int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
-struct mesh_path *mesh_path_lookup(struct ieee80211_sub_if_data *sdata,
+struct mesh_path *mesh_path_lookup(struct mesh_local_bss *mbss,
const u8 *dst);
-struct mesh_path *mpp_path_lookup(struct ieee80211_sub_if_data *sdata,
+struct mesh_path *mpp_path_lookup(struct mesh_local_bss *mbss,
const u8 *dst);
int mpp_path_add(struct ieee80211_sub_if_data *sdata,
const u8 *dst, const u8 *mpp);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 486819c..d8eaccc 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -101,14 +101,14 @@ enum mpath_frame_type {

static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

-static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
- const u8 *orig_addr, __le32 orig_sn,
- u8 target_flags, const u8 *target,
- __le32 target_sn, const u8 *da,
- u8 hop_count, u8 ttl,
- __le32 lifetime, __le32 metric,
- __le32 preq_id,
- struct ieee80211_sub_if_data *sdata)
+static int __mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
+ const u8 *orig_addr, __le32 orig_sn,
+ u8 target_flags, const u8 *target,
+ __le32 target_sn, const u8 *da,
+ u8 hop_count, u8 ttl,
+ __le32 lifetime, __le32 metric,
+ __le32 preq_id,
+ struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
@@ -201,6 +201,38 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
return 0;
}

+static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
+ const u8 *orig_addr, __le32 orig_sn,
+ u8 target_flags, const u8 *target,
+ __le32 target_sn, const u8 *da,
+ u8 hop_count, u8 ttl,
+ __le32 lifetime, __le32 metric,
+ __le32 preq_id,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct mesh_local_bss *mbss = mbss(sdata);
+ struct ieee80211_sub_if_data *tmp_sdata;
+ bool broadcast = is_broadcast_ether_addr(da);
+ struct sta_info *sta;
+ int ret = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp_sdata, &mbss->if_list, u.mesh.if_list) {
+ if (!broadcast) {
+ /* find right outgoing interface */
+ sta = sta_info_get(tmp_sdata, da);
+ if (!sta)
+ continue;
+ }
+ ret = __mesh_path_sel_frame_tx(action, flags, orig_addr,
+ orig_sn, target_flags, target, target_sn,
+ da, hop_count, ttl, lifetime, metric,
+ preq_id, tmp_sdata);
+ }
+ rcu_read_unlock();
+ return ret;
+}
+

/* Headroom is not adjusted. Caller should ensure that skb has sufficient
* headroom in case the frame is encrypted. */
@@ -302,6 +334,8 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
ifmsh->next_perr = TU_TO_EXP_TIME(
ifmsh->mshcfg.dot11MeshHWMPperrMinInterval);
ieee80211_add_pending_skb(local, skb);
+ if (is_multicast_ether_addr(mgmt->da))
+ mesh_bss_forward_tx(sdata, skb);
return 0;
}

@@ -376,6 +410,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
const u8 *hwmp_ie, enum mpath_frame_type action)
{
struct ieee80211_local *local = sdata->local;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath;
struct sta_info *sta;
bool fresh_info;
@@ -423,14 +458,14 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
new_metric = MAX_METRIC;
exp_time = TU_TO_EXP_TIME(orig_lifetime);

- if (ether_addr_equal(orig_addr, sdata->vif.addr)) {
+ if (mesh_bss_matches_addr(mbss, orig_addr)) {
/* This MP is the originator, we are not interested in this
* frame, except for updating transmitter's path info.
*/
process = false;
fresh_info = false;
} else {
- mpath = mesh_path_lookup(sdata, orig_addr);
+ mpath = mesh_path_lookup(mbss, orig_addr);
if (mpath) {
spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_FIXED)
@@ -477,7 +512,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
else {
fresh_info = true;

- mpath = mesh_path_lookup(sdata, ta);
+ mpath = mesh_path_lookup(mbss, ta);
if (mpath) {
spin_lock_bh(&mpath->state_lock);
if ((mpath->flags & MESH_PATH_FIXED) ||
@@ -515,6 +550,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
const u8 *preq_elem, u32 metric)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath = NULL;
const u8 *target_addr, *orig_addr;
const u8 *da;
@@ -537,7 +573,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,

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

- if (ether_addr_equal(target_addr, sdata->vif.addr)) {
+ if (mesh_bss_matches_addr(mbss, target_addr)) {
mhwmp_dbg(sdata, "PREQ is for us\n");
forward = false;
reply = true;
@@ -551,7 +587,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
} else if (is_broadcast_ether_addr(target_addr) &&
(target_flags & IEEE80211_PREQ_TO_FLAG)) {
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, orig_addr);
+ mpath = mesh_path_lookup(mbss, orig_addr);
if (mpath) {
if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) {
reply = true;
@@ -566,7 +602,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
} else {
rcu_read_lock();
- mpath = mesh_path_lookup(sdata, target_addr);
+ mpath = mesh_path_lookup(mbss, target_addr);
if (mpath) {
if ((!(mpath->flags & MESH_PATH_SN_VALID)) ||
SN_LT(mpath->sn, target_sn)) {
@@ -646,12 +682,12 @@ next_hop_deref_protected(struct mesh_path *mpath)
lockdep_is_held(&mpath->state_lock));
}

-
static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
const u8 *prep_elem, u32 metric)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath;
const u8 *target_addr, *orig_addr;
u8 ttl, hopcount, flags;
@@ -662,7 +698,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
PREP_IE_TARGET_ADDR(prep_elem));

orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
- if (ether_addr_equal(orig_addr, sdata->vif.addr))
+ if (mesh_bss_matches_addr(mbss, orig_addr))
/* destination, no forwarding required */
return;

@@ -676,7 +712,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
}

rcu_read_lock();
- mpath = mesh_path_lookup(sdata, orig_addr);
+ mpath = mesh_path_lookup(mbss, orig_addr);
if (mpath)
spin_lock_bh(&mpath->state_lock);
else
@@ -734,7 +770,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
target_rcode = PERR_IE_TARGET_RCODE(perr_elem);

rcu_read_lock();
- mpath = mesh_path_lookup(sdata, target_addr);
+ mpath = mesh_path_lookup(mbss(sdata), target_addr);
if (mpath) {
struct sta_info *sta;

@@ -766,6 +802,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct sta_info *sta;
struct mesh_path *mpath;
u8 ttl, flags, hopcount;
@@ -784,7 +821,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
metric = le32_to_cpu(rann->rann_metric);

/* Ignore our own RANNs */
- if (ether_addr_equal(orig_addr, sdata->vif.addr))
+ if (mesh_bss_matches_addr(mbss, orig_addr))
return;

mhwmp_dbg(sdata,
@@ -800,7 +837,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,

metric_txsta = airtime_link_metric_get(local, sta);

- mpath = mesh_path_lookup(sdata, orig_addr);
+ mpath = mesh_path_lookup(mbss, orig_addr);
if (!mpath) {
mpath = mesh_path_add(sdata, orig_addr);
if (IS_ERR(mpath)) {
@@ -982,6 +1019,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_preq_queue *preq_node;
struct mesh_path *mpath;
u8 ttl, target_flags;
@@ -1003,7 +1041,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);

rcu_read_lock();
- mpath = mesh_path_lookup(sdata, preq_node->dst);
+ mpath = mesh_path_lookup(mbss, preq_node->dst);
if (!mpath)
goto enddiscovery;

@@ -1078,6 +1116,7 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath;
struct sk_buff *skb_to_free = NULL;
u8 *target_addr = hdr->addr3;
@@ -1088,12 +1127,12 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
return 0;

rcu_read_lock();
- err = mesh_nexthop_lookup(sdata, skb);
+ err = mesh_nexthop_lookup(mbss, skb);
if (!err)
goto endlookup;

/* no nexthop found, start resolving */
- mpath = mesh_path_lookup(sdata, target_addr);
+ mpath = mesh_path_lookup(mbss, target_addr);
if (!mpath) {
mpath = mesh_path_add(sdata, target_addr);
if (IS_ERR(mpath)) {
@@ -1122,46 +1161,54 @@ endlookup:
}

/**
- * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame. Calling
- * this function is considered "using" the associated mpath, so preempt a path
- * refresh if this mpath expires soon.
+ * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame and
+ * insert the correct outgoing interface on the skb cb. Calling this function
+ * is considered "using" the associated mpath, so preempt a path refresh if
+ * this mpath expires soon.
*
* @skb: 802.11 frame to be sent
- * @sdata: network subif the frame will be sent through
+ * @mbss: MBSS in which to find a path
*
* Returns: 0 if the next hop was found. Nonzero otherwise.
*/
-int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
+int mesh_nexthop_lookup(struct mesh_local_bss *mbss,
struct sk_buff *skb)
{
+ struct ieee80211_sub_if_data *sdata = NULL;
struct mesh_path *mpath;
struct sta_info *next_hop;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_tx_info *info;
u8 *target_addr = hdr->addr3;
int err = -ENOENT;

rcu_read_lock();
- mpath = mesh_path_lookup(sdata, target_addr);
+ mpath = mesh_path_lookup(mbss, target_addr);

if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
goto endlookup;

- if (time_after(jiffies,
- mpath->exp_time -
- msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
- ether_addr_equal(sdata->vif.addr, hdr->addr4) &&
- !(mpath->flags & MESH_PATH_RESOLVING) &&
- !(mpath->flags & MESH_PATH_FIXED))
- mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
-
next_hop = rcu_dereference(mpath->next_hop);
if (next_hop) {
+ info = IEEE80211_SKB_CB(skb);
+ sdata = mpath->sdata;
+ info->control.vif = &sdata->vif;
memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
ieee80211_mps_set_frame_flags(sdata, next_hop, hdr);
err = 0;
}

+ if (sdata &&
+ time_after(jiffies,
+ mpath->exp_time -
+ msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
+ ether_addr_equal(sdata->vif.addr, hdr->addr4) &&
+ !(mpath->flags & MESH_PATH_RESOLVING) &&
+ !(mpath->flags & MESH_PATH_FIXED))
+ mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+
+
endlookup:
rcu_read_unlock();
return err;
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 89aacfd..993a270 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -184,11 +184,11 @@ errcopy:
return -ENOMEM;
}

-static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata,
+static u32 mesh_table_hash(struct mesh_local_bss *mbss, const u8 *addr,
struct mesh_table *tbl)
{
- /* Use last four bytes of hw addr and interface index as hash index */
- return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex,
+ /* Use last four bytes of hw addr and first four of meshid */
+ return jhash_2words(*(u32 *)(addr+2), *(u32 *) mbss->mesh_id,
tbl->hash_rnd) & tbl->hash_mask;
}

@@ -328,15 +328,14 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath,
spin_unlock_irqrestore(&from_mpath->frame_queue.lock, flags);
}

-
-static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
- struct ieee80211_sub_if_data *sdata)
+static struct mesh_path *__mpath_lookup(struct mesh_table *tbl, const u8 *dst,
+ struct ieee80211_sub_if_data *sdata)
{
struct mesh_path *mpath;
struct hlist_head *bucket;
struct mpath_node *node;

- bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
+ bucket = &tbl->hash_buckets[mesh_table_hash(mbss(sdata), dst, tbl)];
hlist_for_each_entry_rcu(node, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
@@ -352,9 +351,25 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
return NULL;
}

+static struct mesh_path *mpath_lookup(struct mesh_table *tbl,
+ struct mesh_local_bss *mbss,
+ const u8 *dst)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct mesh_path *mpath;
+
+ list_for_each_entry_rcu(sdata, &mbss->if_list, u.mesh.if_list) {
+ mpath = __mpath_lookup(tbl, dst, sdata);
+ if (mpath)
+ return mpath;
+ }
+ return NULL;
+}
+
/**
* mesh_path_lookup - look up a path in the mesh path table
- * @sdata: local subif
+ *
+ * @mbss: MBSS where this destination might be found
* @dst: hardware address (ETH_ALEN length) of destination
*
* Returns: pointer to the mesh path structure, or NULL if not found
@@ -362,15 +377,15 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
* Locking: must be called within a read rcu section.
*/
struct mesh_path *
-mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
+mesh_path_lookup(struct mesh_local_bss *mbss, const u8 *dst)
{
- return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata);
+ return mpath_lookup(rcu_dereference(mesh_paths), mbss, dst);
}

struct mesh_path *
-mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
+mpp_path_lookup(struct mesh_local_bss *mbss, const u8 *dst)
{
- return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata);
+ return mpath_lookup(rcu_dereference(mpp_paths), mbss, dst);
}


@@ -519,7 +534,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
read_lock_bh(&pathtbl_resize_lock);
tbl = resize_dereference_mesh_paths();

- hash_idx = mesh_table_hash(dst, sdata, tbl);
+ hash_idx = mesh_table_hash(mbss(sdata), dst, tbl);
bucket = &tbl->hash_buckets[hash_idx];

spin_lock(&tbl->hashwlock[hash_idx]);
@@ -669,7 +684,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,

tbl = resize_dereference_mpp_paths();

- hash_idx = mesh_table_hash(dst, sdata, tbl);
+ hash_idx = mesh_table_hash(mbss(sdata), dst, tbl);
bucket = &tbl->hash_buckets[hash_idx];

spin_lock(&tbl->hashwlock[hash_idx]);
@@ -862,7 +877,7 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)

read_lock_bh(&pathtbl_resize_lock);
tbl = resize_dereference_mesh_paths();
- hash_idx = mesh_table_hash(addr, sdata, tbl);
+ hash_idx = mesh_table_hash(mbss(sdata), addr, tbl);
bucket = &tbl->hash_buckets[hash_idx];

spin_lock(&tbl->hashwlock[hash_idx]);
@@ -1028,7 +1043,7 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
node = hlist_entry(p, struct mpath_node, list);
mpath = node->mpath;
new_node->mpath = mpath;
- hash_idx = mesh_table_hash(mpath->dst, mpath->sdata, newtbl);
+ hash_idx = mesh_table_hash(mbss(mpath->sdata), mpath->dst, newtbl);
hlist_add_head(&new_node->list,
&newtbl->hash_buckets[hash_idx]);
return 0;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 22e412b..4e7886d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2006,6 +2006,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
struct sk_buff *skb = rx->skb, *fwd_skb;
struct ieee80211_local *local = rx->local;
struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct mesh_local_bss *mbss = mbss(sdata);
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
__le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
@@ -2059,7 +2060,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
}

rcu_read_lock();
- mppath = mpp_path_lookup(sdata, proxied_addr);
+ mppath = mpp_path_lookup(mbss, proxied_addr);
if (!mppath) {
mpp_path_add(sdata, proxied_addr, mpp_addr);
} else {
@@ -2110,7 +2111,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
/* update power mode indication when forwarding */
ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
- } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
+ } else if (!mesh_nexthop_lookup(mbss, fwd_skb)) {
/* mesh power mode flags updated in mesh_nexthop_lookup */
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
} else {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4a5fbf8..c132c76 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1799,7 +1799,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct sta_info *next_hop;
bool mpp_lookup = true;

- mpath = mesh_path_lookup(sdata, skb->data);
+ mpath = mesh_path_lookup(mbss(sdata), skb->data);
if (mpath) {
mpp_lookup = false;
next_hop = rcu_dereference(mpath->next_hop);
@@ -1810,7 +1810,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
}

if (mpp_lookup)
- mppath = mpp_path_lookup(sdata, skb->data);
+ mppath = mpp_path_lookup(mbss(sdata),
+ skb->data);

if (mppath && mpath)
mesh_path_del(mpath->sdata, mpath->dst);
--
1.7.10.4


2013-05-07 13:42:41

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 06/12] mac80211: notify bridge when leaving mesh

On Thu, 2013-05-02 at 19:33 -0700, Thomas Pedersen wrote:
> After turning carrier off, any parent bridge interface
> needs to be notified. Otherwise we would see a panic when
> attempting to transmit frames on a mesh interface which
> hadn't yet been put down.
>
> Signed-off-by: Thomas Pedersen <[email protected]>
> ---
> net/mac80211/mesh.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
> index eac9988..271ddc9 100644
> --- a/net/mac80211/mesh.c
> +++ b/net/mac80211/mesh.c
> @@ -993,6 +993,9 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
> struct beacon_data *bcn;
>
> netif_carrier_off(sdata->dev);
> + if (sdata->dev->priv_flags & IFF_BRIDGE_PORT)
> + /* stop bridge transmissions */
> + call_netdevice_notifiers(NETDEV_CHANGE, sdata->dev);

Err, this seems like a really bad hack? I don't really think drivers
should call that?

johannes


2013-05-07 13:44:04

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 00/12] MBSS sharing across multiple interfaces

On Thu, 2013-05-02 at 19:33 -0700, Thomas Pedersen wrote:
> This patchset enables multiple interfaces on the same host to share mesh path
> selection and frame forwarding duties. The peering state machine remains
> per-interface.

Generally, this looks pretty good. The one thing I didn't see (maybe I
missed it) is how you handle different headroom/tailroom/crypto
requirements for different devices?

johannes


2013-05-03 02:36:35

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 11/12] {nl,mac}80211: specify MBSS sharing on/off

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/net/cfg80211.h | 3 +++
include/uapi/linux/nl80211.h | 5 +++++
net/mac80211/cfg.c | 1 +
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mesh.c | 4 +++-
net/wireless/mesh.c | 1 +
net/wireless/nl80211.c | 3 +++
7 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 26e9113..21007e7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1169,6 +1169,8 @@ struct mesh_config {
* @dtim_period: DTIM period to use
* @beacon_interval: beacon interval to use
* @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
+ * @shared: MBSS sharing and intra-vif data forwarding may take place for
+ * this mesh setup.
*
* These parameters are fixed when the mesh is created.
*/
@@ -1187,6 +1189,7 @@ struct mesh_setup {
u8 dtim_period;
u16 beacon_interval;
int mcast_rate[IEEE80211_NUM_BANDS];
+ bool shared;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b484307..549ce133 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2645,6 +2645,10 @@ enum nl80211_meshconf_params {
* @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will
* implement an MPM which handles peer allocation and state.
*
+ * @NL80211_MESH_SETUP_CAN_SHARE: Enable this option to allow sharing an MBSS
+ * profile and frame forwarding across multiple virtual interfaces with the
+ * same profile. Defaults to off.
+ *
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
*
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -2658,6 +2662,7 @@ enum nl80211_mesh_setup_params {
NL80211_MESH_SETUP_USERSPACE_AMPE,
NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
NL80211_MESH_SETUP_USERSPACE_MPM,
+ NL80211_MESH_SETUP_CAN_SHARE,

/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 76e9575..398df0a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1742,6 +1742,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
/* now copy the rest of the setup parameters */
ifmsh->mesh_id_len = setup->mesh_id_len;
memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
+ ifmsh->share_mbss = setup->shared;
ifmsh->mesh_sp_id = setup->sync_method;
ifmsh->mesh_pp_id = setup->path_sel_proto;
ifmsh->mesh_pm_id = setup->path_metric;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a8b33d2..19c0ff4 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -632,6 +632,7 @@ struct ieee80211_if_mesh {
struct ps_data ps;

/* mbss sharing */
+ bool share_mbss;
struct mesh_local_bss *mesh_bss;
struct list_head if_list;
};
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 9445f02..08d3171 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -60,6 +60,7 @@ mesh_bss_matches(struct ieee80211_sub_if_data *sdata,
struct mesh_local_bss *mbss)
{
return mbss->can_share &&
+ setup->shared &&
mbss->mesh_id_len == setup->mesh_id_len &&
memcmp(mbss->mesh_id, setup->mesh_id, mbss->mesh_id_len) == 0 &&
mbss->path_sel_proto == setup->path_sel_proto &&
@@ -109,7 +110,7 @@ mesh_bss_create(struct ieee80211_sub_if_data *sdata, struct mesh_setup *setup)

mbss->mesh_id_len = setup->mesh_id_len;
memcpy(mbss->mesh_id, setup->mesh_id, setup->mesh_id_len);
- mbss->can_share = false;
+ mbss->can_share = setup->shared;
mbss->path_metric = setup->path_metric;
mbss->path_sel_proto = setup->path_sel_proto;
mbss->sync_method = setup->sync_method;
@@ -994,6 +995,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
setup.sync_method = ifmsh->mesh_pm_id;
setup.path_metric = ifmsh->mesh_cc_id;
setup.is_secure = ifmsh->security & IEEE80211_MESH_SEC_SECURED;
+ setup.shared = ifmsh->share_mbss;

ret = mesh_bss_add(sdata, &setup);
if (ret) {
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 0bb93f3..cb1e360 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -88,6 +88,7 @@ const struct mesh_setup default_mesh_setup = {
.user_mpm = false,
.beacon_interval = MESH_DEFAULT_BEACON_INTERVAL,
.dtim_period = MESH_DEFAULT_DTIM_PERIOD,
+ .shared = false,
};

int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9cdcd9e..5925b13 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4857,6 +4857,9 @@ static int nl80211_parse_mesh_setup(struct genl_info *info,
if (setup->is_secure)
setup->user_mpm = true;

+ if (tb[NL80211_MESH_SETUP_CAN_SHARE])
+ setup->shared = nla_get_u8(tb[NL80211_MESH_SETUP_CAN_SHARE]);
+
return 0;
}

--
1.7.10.4


2013-05-03 02:36:13

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 02/12] mac80211: mesh: add function to tx on all other mbss ifaces

From: Bob Copeland <[email protected]>

Add a function to rebroadcast mcast/bcast frames on other
interfaces when multiple interfaces are shared in an mbss.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh.c | 43 +++++++++++++++++++++++++++++++++++++++++++
net/mac80211/mesh.h | 4 ++++
2 files changed, 47 insertions(+)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 5ea4812..eac9988 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
#include "ieee80211_i.h"
+#include "wme.h"
#include "mesh.h"

static int mesh_allocated;
@@ -202,6 +203,48 @@ bool mesh_bss_matches_addr(struct mesh_local_bss *mbss, const u8 *addr)
}

/**
+ * mesh_bss_forward_tx - send a frame on all other interfaces in a bss
+ *
+ * @sdata: interface to exclude from tx
+ * @skb: frame to send
+ *
+ * Forwards group-directed frames from sdata for tx on all other interfaces
+ * which are participating in an mbss.
+ */
+void mesh_bss_forward_tx(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ struct mesh_local_bss *mbss = mbss(sdata);
+ struct ieee80211_hdr *fwd_hdr;
+ struct sk_buff *fwd_skb;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_sub_if_data *tmp_sdata;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(tmp_sdata, &mbss->if_list, u.mesh.if_list) {
+
+ if (sdata == tmp_sdata)
+ continue;
+
+ fwd_skb = skb_copy(skb, GFP_ATOMIC);
+ if (!fwd_skb)
+ goto out;
+
+ fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
+ info = IEEE80211_SKB_CB(fwd_skb);
+ memset(info, 0, sizeof(*info));
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.vif = &tmp_sdata->vif;
+
+ memcpy(fwd_hdr->addr2, tmp_sdata->vif.addr, ETH_ALEN);
+ ieee80211_set_qos_hdr(tmp_sdata, fwd_skb);
+ ieee80211_add_pending_skb(tmp_sdata->local, fwd_skb);
+ }
+out:
+ rcu_read_unlock();
+}
+
+/**
* mesh_matches_local - check if the config of a mesh point matches ours
*
* @sdata: local mesh subif
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index f23b58f..4a1a15e 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -361,6 +361,8 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
void ieee80211s_stop(void);
+void mesh_bss_forward_tx(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
struct ieee80211_sub_if_data *
mesh_bss_find_if(struct mesh_local_bss *mbss, const u8 *addr);
bool mesh_bss_matches_addr(struct mesh_local_bss *mbss, const u8 *addr);
@@ -373,6 +375,8 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
{}
static inline void ieee80211s_stop(void) {}
+static inline void mesh_bss_forward_tx(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb) {}
#endif

#endif /* IEEE80211S_H */
--
1.7.10.4


2013-05-29 16:12:01

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [RFC 06/12] mac80211: notify bridge when leaving mesh

On Tue, May 28, 2013 at 10:01 AM, Thomas Pedersen <[email protected]> wrote:
> On Fri, May 24, 2013 at 1:32 PM, Johannes Berg
> <[email protected]> wrote:
>> On Tue, 2013-05-21 at 18:09 -0700, Thomas Pedersen wrote:
>>> Hey, Sorry for the late response.
>>
>> Me too :)
>>
>>> >> netif_carrier_off(sdata->dev);
>>> >> + if (sdata->dev->priv_flags & IFF_BRIDGE_PORT)
>>> >> + /* stop bridge transmissions */
>>> >> + call_netdevice_notifiers(NETDEV_CHANGE, sdata->dev);
>>> >
>>> > Err, this seems like a really bad hack? I don't really think drivers
>>> > should call that?
>>>
>>> Why not? We're just notifying the bridge interface that this port has
>>> gone down, to avoid dereferencing a null pointer (on bridge flood
>>> traffic) after the mesh_bss has been removed.
>>>
>>> Is cfg80211_leave_mesh() an acceptable location for this fix?
>>
>> I'm not really convinced it's an acceptable fix in itself? Why should we
>> ever have to call netdev notifiers, that seems odd to me. Also why would
>> that prevent a crash? Wouldn't we just drop packets for the mesh if we
>> aren't joined in a mesh any more? Or something like that Accessing the
>> priv flags and then calling the netdev notifiers seems really strange to
>> me. If this was necessary, then wouldn't netif_carrier_off() do it
>> internally?
>
> OK I'll take a look at this and figure out a cleaner solution then. Thanks.

After reverting this patch I can no longer trigger the crash it was
supposed to fix. Either something changed in the rebase, or it was
never needed. Will drop from the resubmission for now.

Thanks,
--
Thomas

2013-05-03 13:25:38

by Chaoxing Lin

[permalink] [raw]
Subject: RE: [RFC 00/12] MBSS sharing across multiple interfaces

I have some questions and comments.

Question 1

The typical use case of multiple interfaces on this same host is to do RF segregation in order to improve overall network performance. e.g. divide a original mesh of 16 radios into 2 meshes of 8 radios each. This multi-radio host bridges these two small meshes which are on different channels. I can't see why user would put multiple radios of the same host on the same channel. They would just interfere with each other very badly.

So, it does not matter whether they have matching mesh setup profile or not. Two MBSS-es simply can't see each other in air.

Question 2

In MPP where there are multiple mesh interfaces, AP interface and/or Ethernet interface, how does this "MBSS sharing" work?
a. add both mesh interface in 802.1d bridge, or
b. add either interface in bridge, or
c. sharing can't be used




-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Thomas Pedersen
Sent: Thursday, May 02, 2013 10:34 PM
To: Johannes Berg
Cc: open80211s; linux-wirelss
Subject: [RFC 00/12] MBSS sharing across multiple interfaces

This patchset enables multiple interfaces on the same host to share mesh path selection and frame forwarding duties. The peering state machine remains per-interface.

The user interface looks something like:

iw wlan0 mesh join foo shared on
iw wlan1 mesh join foo shared on

As long as wlan0 and wlan1 have a matching mesh setup profile, they will be considered part of the same MBSS.

This approach is superior to simple 802.1d briding, since mac80211 can dynamically pick the better link instead of simply disabling an entire port.
The added link knowledge also enables bonding and alternation in the future.

Bob Copeland (6):
mac80211: track and share mesh BSSes among interfaces
mac80211: mesh: add function to tx on all other mbss ifaces
mac80211: use all MBSS interfaces for path selection
mac80211: forward group frames on mbss-shared interfaces
mac80211: add shared-mbss transmit path
mac08211: add shared-mbss receive path handling

Thomas Pedersen (6):
mac80211: assign outgoing interface with nexthop
mac80211: forward frames on correct mbss-shared interface
mac80211: notify bridge when leaving mesh
mac80211: make RMC per-mbss
{nl,mac}80211: specify MBSS sharing on/off
{nl,mac}80211: allow mpath dump to span local MBSS

include/net/cfg80211.h | 8 +-
include/uapi/linux/nl80211.h | 12 +-
net/mac80211/cfg.c | 17 +--
net/mac80211/ieee80211_i.h | 37 +++++-
net/mac80211/iface.c | 3 -
net/mac80211/mesh.c | 276 +++++++++++++++++++++++++++++++++++++++---
net/mac80211/mesh.h | 24 ++--
net/mac80211/mesh_hwmp.c | 133 ++++++++++++++------
net/mac80211/mesh_pathtbl.c | 68 +++++++----
net/mac80211/rx.c | 110 +++++++++++++----
net/mac80211/tx.c | 8 +-
net/wireless/mesh.c | 1 +
net/wireless/nl80211.c | 21 +++-
net/wireless/rdev-ops.h | 10 +-
14 files changed, 599 insertions(+), 129 deletions(-)

--
1.7.10.4

_______________________________________________
Devel mailing list
[email protected]
http://lists.open80211s.org/cgi-bin/mailman/listinfo/devel

2013-05-03 02:36:11

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 01/12] mac80211: track and share mesh BSSes among interfaces

From: Bob Copeland <[email protected]>

Add a new global list of mesh BSSes for this host. Each struct
mesh_local_bss contains parameters specific to a mesh instance,
as well as a list of interfaces participating in the MBSS. This
will enable lookup of other interfaces on the host participating
in the same mesh.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/ieee80211_i.h | 33 +++++++++
net/mac80211/mesh.c | 172 ++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/mesh.h | 4 ++
3 files changed, 209 insertions(+)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 44be28c..da7fbd4 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -285,6 +285,35 @@ struct mesh_stats {
__u32 dropped_frames_congestion;/* Not forwarded due to congestion */
};

+/**
+ * mesh_local_bss - a mesh BSS running on this host
+ *
+ * @mesh_id: the mesh id
+ * @mesh_id_len: size of mesh id in bytes
+ * @sync_method: which synchronization method to use
+ * @path_sel_proto: which path selection protocol to use
+ * @path_metric: which metric to use
+ * @is_secure: true if the mesh is secure
+ * @can_share: true if this bss can be shared (user-configurable per-if)
+ * @net: network namespace devices in this mbss belong to
+ * @list: listptr for siblings in mesh_bss_list
+ * @if_list: interfaces sharing this bss
+ */
+struct mesh_local_bss {
+ u8 mesh_id[IEEE80211_MAX_SSID_LEN];
+ u8 mesh_id_len;
+ u8 sync_method;
+ u8 path_sel_proto;
+ u8 path_metric;
+ bool is_secure;
+
+ bool can_share;
+ struct net *net;
+
+ struct list_head list;
+ struct list_head if_list;
+};
+
#define PREQ_Q_F_START 0x1
#define PREQ_Q_F_REFRESH 0x2
struct mesh_preq_queue {
@@ -600,6 +629,10 @@ struct ieee80211_if_mesh {
int ps_peers_light_sleep;
int ps_peers_deep_sleep;
struct ps_data ps;
+
+ /* mbss sharing */
+ struct mesh_local_bss *mesh_bss;
+ struct list_head if_list;
};

#ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 6952760..5ea4812 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -16,6 +16,10 @@
static int mesh_allocated;
static struct kmem_cache *rm_cache;

+/* mesh_bss_mtx protects updates; internal iface list uses RCU */
+static DEFINE_MUTEX(mesh_bss_mtx);
+static LIST_HEAD(mesh_bss_list);
+
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
{
return (mgmt->u.action.u.mesh_action.action_code ==
@@ -49,6 +53,154 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
ieee80211_queue_work(&local->hw, &sdata->work);
}

+static inline bool
+mesh_bss_matches(struct ieee80211_sub_if_data *sdata,
+ struct mesh_setup *setup,
+ struct mesh_local_bss *mbss)
+{
+ return mbss->can_share &&
+ mbss->mesh_id_len == setup->mesh_id_len &&
+ memcmp(mbss->mesh_id, setup->mesh_id, mbss->mesh_id_len) == 0 &&
+ mbss->path_sel_proto == setup->path_sel_proto &&
+ mbss->path_metric == setup->path_metric &&
+ mbss->sync_method == setup->sync_method &&
+ mbss->is_secure == setup->is_secure &&
+ net_eq(wiphy_net(sdata->wdev.wiphy), mbss->net);
+}
+
+static struct mesh_local_bss * __must_check
+mesh_bss_find(struct ieee80211_sub_if_data *sdata, struct mesh_setup *setup)
+{
+ struct mesh_local_bss *mbss;
+
+ if (WARN_ON(!setup->mesh_id_len))
+ return NULL;
+
+ lockdep_assert_held(&mesh_bss_mtx);
+
+ list_for_each_entry(mbss, &mesh_bss_list, list)
+ if (mesh_bss_matches(sdata, setup, mbss))
+ return mbss;
+
+ return NULL;
+}
+
+static struct mesh_local_bss * __must_check
+mesh_bss_create(struct ieee80211_sub_if_data *sdata, struct mesh_setup *setup)
+{
+ struct mesh_local_bss *mbss;
+
+ lockdep_assert_held(&mesh_bss_mtx);
+
+ if (WARN_ON(setup->mesh_id_len > IEEE80211_MAX_SSID_LEN))
+ return NULL;
+
+ mbss = kzalloc(sizeof(*mbss), GFP_KERNEL);
+ if (!mbss)
+ return NULL;
+
+ INIT_LIST_HEAD(&mbss->if_list);
+
+ mbss->mesh_id_len = setup->mesh_id_len;
+ memcpy(mbss->mesh_id, setup->mesh_id, setup->mesh_id_len);
+ mbss->can_share = false;
+ mbss->path_metric = setup->path_metric;
+ mbss->path_sel_proto = setup->path_sel_proto;
+ mbss->sync_method = setup->sync_method;
+ mbss->is_secure = setup->is_secure;
+ mbss->net = wiphy_net(sdata->wdev.wiphy);
+ return mbss;
+}
+
+static void mesh_bss_remove(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct mesh_local_bss *mbss = ifmsh->mesh_bss;
+
+ if (!mbss)
+ return;
+
+ mutex_lock(&mesh_bss_mtx);
+ list_del_rcu(&ifmsh->if_list);
+ synchronize_rcu();
+ ifmsh->mesh_bss = NULL;
+
+ /* free when no more devs have this mbss */
+ if (list_empty(&mbss->if_list)) {
+ list_del(&mbss->list);
+ kfree(mbss);
+ }
+ mutex_unlock(&mesh_bss_mtx);
+}
+
+static
+int mesh_bss_add(struct ieee80211_sub_if_data *sdata,
+ struct mesh_setup *setup)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ struct mesh_local_bss *mbss;
+ int ret;
+
+ if (WARN_ON(!setup->mesh_id_len))
+ return -EINVAL;
+
+ mutex_lock(&mesh_bss_mtx);
+ mbss = mesh_bss_find(sdata, setup);
+ if (!mbss) {
+ mbss = mesh_bss_create(sdata, setup);
+ if (!mbss) {
+ ret = -ENOMEM;
+ goto out_fail;
+ }
+ list_add(&mbss->list, &mesh_bss_list);
+ }
+
+ ifmsh->mesh_bss = mbss;
+ list_add_rcu(&ifmsh->if_list, &mbss->if_list);
+ ret = 0;
+
+ out_fail:
+ mutex_unlock(&mesh_bss_mtx);
+ return ret;
+}
+
+/**
+ * mesh_bss_find_if - return the interface in the local mbss matching addr
+ *
+ * @mbss: mesh bss on this host
+ * @addr: address to find in the interface list
+ *
+ * Returns an interface in mbss matching addr, or NULL if none found.
+ */
+struct ieee80211_sub_if_data *
+mesh_bss_find_if(struct mesh_local_bss *mbss, const u8 *addr)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &mbss->if_list, u.mesh.if_list) {
+ if (ether_addr_equal(addr, sdata->vif.addr)) {
+ rcu_read_unlock();
+ return sdata;
+ }
+ }
+ rcu_read_unlock();
+ return NULL;
+}
+
+/**
+ * mesh_bss_matches_addr - check if the specified addr is in the local mbss
+ *
+ * @mbss: mesh bss on this host
+ * @addr: address to find in the interface list
+ *
+ * Returns true if the addr is used by an interface in the mbss.
+ */
+bool mesh_bss_matches_addr(struct mesh_local_bss *mbss, const u8 *addr)
+{
+ return mesh_bss_find_if(mbss, addr) != NULL;
+}
+
/**
* mesh_matches_local - check if the config of a mesh point matches ours
*
@@ -733,6 +885,9 @@ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,

int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
{
+ struct mesh_setup setup = {};
+ int ret;
+
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
u32 changed = BSS_CHANGED_BEACON |
@@ -769,6 +924,19 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
return -ENOMEM;
}

+ setup.mesh_id_len = ifmsh->mesh_id_len;
+ setup.mesh_id = ifmsh->mesh_id;
+ setup.path_sel_proto = ifmsh->mesh_pp_id;
+ setup.sync_method = ifmsh->mesh_pm_id;
+ setup.path_metric = ifmsh->mesh_cc_id;
+ setup.is_secure = ifmsh->security & IEEE80211_MESH_SEC_SECURED;
+
+ ret = mesh_bss_add(sdata, &setup);
+ if (ret) {
+ ieee80211_stop_mesh(sdata);
+ return ret;
+ }
+
ieee80211_bss_info_change_notify(sdata, changed);

netif_carrier_on(sdata->dev);
@@ -818,6 +986,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
local->fif_other_bss--;
atomic_dec(&local->iff_allmultis);
ieee80211_configure_filter(local);
+
+ netif_tx_stop_all_queues(sdata->dev);
+
+ mesh_bss_remove(sdata);
}

static void
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index da15877..f23b58f 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -361,6 +361,10 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
void ieee80211s_stop(void);
+struct ieee80211_sub_if_data *
+mesh_bss_find_if(struct mesh_local_bss *mbss, const u8 *addr);
+bool mesh_bss_matches_addr(struct mesh_local_bss *mbss, const u8 *addr);
+#define mbss(sdata) (sdata->u.mesh.mesh_bss)
#else
static inline void
ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
--
1.7.10.4


2013-05-03 02:36:30

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 09/12] mac80211: add shared-mbss transmit path

From: Bob Copeland <[email protected]>

Transmit locally-originated group data frames on every interface
so that members of the mesh on every channel will see the frame.

For individually-addressed frames, when we resolve the next
hop, the outgoing interface might be different than the
originator if the best path is on a different channel.
Requeue such frames on the correct interface's pending queue.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_hwmp.c | 12 +++++++++++-
net/mac80211/tx.c | 3 +++
2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index d8eaccc..6ba483e 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -1115,6 +1115,7 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_sub_if_data *dest_sdata;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct mesh_local_bss *mbss = mbss(sdata);
struct mesh_path *mpath;
@@ -1128,8 +1129,17 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,

rcu_read_lock();
err = mesh_nexthop_lookup(mbss, skb);
- if (!err)
+ if (!err) {
+ dest_sdata = vif_to_sdata(info->control.vif);
+ /* requeue if mesh path uses a different interface */
+ if (dest_sdata != sdata) {
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ ieee80211_set_qos_hdr(dest_sdata, skb);
+ ieee80211_add_pending_skb(dest_sdata->local, skb);
+ err = -EAGAIN;
+ }
goto endlookup;
+ }

/* no nexthop found, start resolving */
mpath = mesh_path_lookup(mbss, target_addr);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c132c76..4b28680 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1452,6 +1452,9 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
} else {
ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
}
+ if (is_multicast_ether_addr(hdr->addr1) &&
+ ieee80211_is_data(hdr->frame_control))
+ mesh_bss_forward_tx(sdata, skb);
}

ieee80211_set_qos_hdr(sdata, skb);
--
1.7.10.4


2013-05-03 02:36:18

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 04/12] mac80211: assign outgoing interface with nexthop

When updated mpath routing info is found, the new route
may be on a different interface (in the case of MBSS
sharing).

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 993a270..7df8f27 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -195,27 +195,34 @@ static u32 mesh_table_hash(struct mesh_local_bss *mbss, const u8 *addr,

/**
*
- * mesh_path_assign_nexthop - update mesh path next hop
+ * mesh_path_assign_nexthop - update mesh path info
*
* @mpath: mesh path to update
* @sta: next hop to assign
*
+ * Updates queued frames and outgoing interface.
+ *
* Locking: mpath->state_lock must be held when calling this function
*/
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_tx_info *info;
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
unsigned long flags;

rcu_assign_pointer(mpath->next_hop, sta);
+ mpath->sdata = sdata;

spin_lock_irqsave(&mpath->frame_queue.lock, flags);
skb_queue_walk(&mpath->frame_queue, skb) {
+ info = IEEE80211_SKB_CB(skb);
hdr = (struct ieee80211_hdr *) skb->data;
memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
- memcpy(hdr->addr2, mpath->sdata->vif.addr, ETH_ALEN);
- ieee80211_mps_set_frame_flags(sta->sdata, sta, hdr);
+ memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
+ info->control.vif = &sdata->vif;
+ ieee80211_mps_set_frame_flags(sdata, sta, hdr);
}

spin_unlock_irqrestore(&mpath->frame_queue.lock, flags);
--
1.7.10.4


2013-05-28 17:02:16

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [RFC 06/12] mac80211: notify bridge when leaving mesh

On Fri, May 24, 2013 at 1:32 PM, Johannes Berg
<[email protected]> wrote:
> On Tue, 2013-05-21 at 18:09 -0700, Thomas Pedersen wrote:
>> Hey, Sorry for the late response.
>
> Me too :)
>
>> >> netif_carrier_off(sdata->dev);
>> >> + if (sdata->dev->priv_flags & IFF_BRIDGE_PORT)
>> >> + /* stop bridge transmissions */
>> >> + call_netdevice_notifiers(NETDEV_CHANGE, sdata->dev);
>> >
>> > Err, this seems like a really bad hack? I don't really think drivers
>> > should call that?
>>
>> Why not? We're just notifying the bridge interface that this port has
>> gone down, to avoid dereferencing a null pointer (on bridge flood
>> traffic) after the mesh_bss has been removed.
>>
>> Is cfg80211_leave_mesh() an acceptable location for this fix?
>
> I'm not really convinced it's an acceptable fix in itself? Why should we
> ever have to call netdev notifiers, that seems odd to me. Also why would
> that prevent a crash? Wouldn't we just drop packets for the mesh if we
> aren't joined in a mesh any more? Or something like that Accessing the
> priv flags and then calling the netdev notifiers seems really strange to
> me. If this was necessary, then wouldn't netif_carrier_off() do it
> internally?

OK I'll take a look at this and figure out a cleaner solution then. Thanks.

--
Thomas

2013-05-03 02:36:37

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 12/12] {nl,mac}80211: allow mpath dump to span local MBSS

Allow the user to specify a flag
NL80211_ATTR_MPATH_DUMP_MBSS along with an mpath dump
request to dump all paths in the interface's mbss.

Signed-off-by: Thomas Pedersen <[email protected]>
---
include/net/cfg80211.h | 5 +++--
include/uapi/linux/nl80211.h | 7 +++++--
net/mac80211/cfg.c | 8 +++++---
net/mac80211/mesh.h | 3 ++-
net/mac80211/mesh_pathtbl.c | 8 ++++++--
net/wireless/nl80211.c | 18 +++++++++++++++---
net/wireless/rdev-ops.h | 10 ++++++----
7 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 21007e7..fa9a6e6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2087,8 +2087,9 @@ struct cfg80211_ops {
u8 *dst, u8 *next_hop,
struct mpath_info *pinfo);
int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
- int idx, u8 *dst, u8 *next_hop,
- struct mpath_info *pinfo);
+ int idx, struct net_device **pathdev,
+ u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo, bool mbss);
int (*get_mesh_config)(struct wiphy *wiphy,
struct net_device *dev,
struct mesh_config *conf);
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 549ce133..6c1a03e 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -205,8 +205,9 @@
* by %NL80211_ATTR_IFINDEX.
*
* @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
- * destination %NL80211_ATTR_MAC on the interface identified by
- * %NL80211_ATTR_IFINDEX.
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX. If %NL80211_ATTR_MPATH_MBSS is set, get all
+ * mpaths in mbss, not just ones matched by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
* destination %NL80211_ATTR_MAC on the interface identified by
* %NL80211_ATTR_IFINDEX.
@@ -1729,6 +1730,8 @@ enum nl80211_attrs {
NL80211_ATTR_CRIT_PROT_ID,
NL80211_ATTR_MAX_CRIT_PROT_DURATION,

+ NL80211_ATTR_MPATH_DUMP_MBSS,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 398df0a..ff713d5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1681,8 +1681,9 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
}

static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
- int idx, u8 *dst, u8 *next_hop,
- struct mpath_info *pinfo)
+ int idx, struct net_device **pathdev,
+ u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo, bool mbss)
{
struct ieee80211_sub_if_data *sdata;
struct mesh_path *mpath;
@@ -1690,13 +1691,14 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);

rcu_read_lock();
- mpath = mesh_path_lookup_by_idx(sdata, idx);
+ mpath = mesh_path_lookup_by_idx(sdata, idx, mbss);
if (!mpath) {
rcu_read_unlock();
return -ENOENT;
}
memcpy(dst, mpath->dst, ETH_ALEN);
mpath_set_pinfo(mpath, next_hop, pinfo);
+ *pathdev = mpath->sdata->wdev.netdev;
rcu_read_unlock();
return 0;
}
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index bf108ef..31b60f1 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -271,7 +271,8 @@ struct mesh_path *mpp_path_lookup(struct mesh_local_bss *mbss,
int mpp_path_add(struct ieee80211_sub_if_data *sdata,
const u8 *dst, const u8 *mpp);
struct mesh_path *
-mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
+mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata,
+ int idx, bool mbss);
void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 7df8f27..01b5738 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -400,13 +400,15 @@ mpp_path_lookup(struct mesh_local_bss *mbss, const u8 *dst)
* mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
* @idx: index
* @sdata: local subif, or NULL for all entries
+ * @mbss: match @idx against all mpaths in sdata's MBSS
*
* Returns: pointer to the mesh path structure, or NULL if not found.
*
* Locking: must be called within a read rcu section.
*/
struct mesh_path *
-mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
+mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata,
+ int idx, bool mbss)
{
struct mesh_table *tbl = rcu_dereference(mesh_paths);
struct mpath_node *node;
@@ -414,7 +416,9 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
int j = 0;

for_each_mesh_entry(tbl, node, i) {
- if (sdata && node->mpath->sdata != sdata)
+ if (mbss && mbss(sdata) != mbss(node->mpath->sdata))
+ continue;
+ if (!mbss && sdata && sdata != node->mpath->sdata)
continue;
if (j++ == idx) {
if (mpath_expired(node->mpath)) {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5925b13..f95dfff 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -270,6 +270,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_MESH_ID_LEN },
[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
+ [NL80211_ATTR_MPATH_DUMP_MBSS] = { .type = NLA_FLAG },

[NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
[NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
@@ -4222,9 +4223,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
struct mpath_info pinfo;
struct cfg80211_registered_device *dev;
struct wireless_dev *wdev;
+ struct net_device *pathdev;
u8 dst[ETH_ALEN];
u8 next_hop[ETH_ALEN];
int path_idx = cb->args[2];
+ struct nlattr **tb = nl80211_fam.attrbuf;
+ bool mbss = false;
int err;

err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
@@ -4241,9 +4245,17 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
goto out_err;
}

+ err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+ tb, nl80211_fam.maxattr, nl80211_policy);
+ if (err)
+ return err;
+
+ mbss = nla_get_flag(tb[NL80211_ATTR_MPATH_DUMP_MBSS]);
+
while (1) {
- err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst,
- next_hop, &pinfo);
+ err = rdev_dump_mpath(dev, wdev->netdev, path_idx,
+ &pathdev, dst, next_hop,
+ &pinfo, mbss);
if (err == -ENOENT)
break;
if (err)
@@ -4251,7 +4263,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,

if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
- wdev->netdev, dst, next_hop,
+ pathdev, dst, next_hop,
&pinfo) < 0)
goto out;

diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 9f15f0a..a543601 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -264,14 +264,16 @@ static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev,
}

static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
- struct net_device *dev, int idx, u8 *dst,
- u8 *next_hop, struct mpath_info *pinfo)
+ struct net_device *dev, int idx,
+ struct net_device **pathdev,
+ u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo, bool mbss)

{
int ret;
trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
- ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
- pinfo);
+ ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, pathdev,
+ dst, next_hop, pinfo, mbss);
trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
return ret;
}
--
1.7.10.4


2013-05-22 01:09:53

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [RFC 06/12] mac80211: notify bridge when leaving mesh

Hey, Sorry for the late response.

On Tue, May 7, 2013 at 6:42 AM, Johannes Berg <[email protected]> wrote:
> On Thu, 2013-05-02 at 19:33 -0700, Thomas Pedersen wrote:
>> After turning carrier off, any parent bridge interface
>> needs to be notified. Otherwise we would see a panic when
>> attempting to transmit frames on a mesh interface which
>> hadn't yet been put down.
>>
>> Signed-off-by: Thomas Pedersen <[email protected]>
>> ---
>> net/mac80211/mesh.c | 3 +++
>> 1 file changed, 3 insertions(+)
>>
>> diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
>> index eac9988..271ddc9 100644
>> --- a/net/mac80211/mesh.c
>> +++ b/net/mac80211/mesh.c
>> @@ -993,6 +993,9 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
>> struct beacon_data *bcn;
>>
>> netif_carrier_off(sdata->dev);
>> + if (sdata->dev->priv_flags & IFF_BRIDGE_PORT)
>> + /* stop bridge transmissions */
>> + call_netdevice_notifiers(NETDEV_CHANGE, sdata->dev);
>
> Err, this seems like a really bad hack? I don't really think drivers
> should call that?

Why not? We're just notifying the bridge interface that this port has
gone down, to avoid dereferencing a null pointer (on bridge flood
traffic) after the mesh_bss has been removed.

Is cfg80211_leave_mesh() an acceptable location for this fix?

--
Thomas

2013-05-07 13:37:47

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 01/12] mac80211: track and share mesh BSSes among interfaces

Ok this is big ... Let me tackle it patch by patch I guess :-)

> +struct mesh_local_bss {

> + bool can_share;

Does that even make sense? I mean, wouldn't you simply not link/create
such an entry if the given vif can't share?

> @@ -818,6 +986,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
> local->fif_other_bss--;
> atomic_dec(&local->iff_allmultis);
> ieee80211_configure_filter(local);
> +
> + netif_tx_stop_all_queues(sdata->dev);

how is that related to this patch?

johannes


2013-05-03 02:36:25

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 07/12] mac80211: make RMC per-mbss

The RMC was previously per-sdata, but it is sufficient for
one of the interfaces in a local mbss to receive a
multicast frame once.

Once multiple interfaces share the same mesh data forwarding
duties, we may inadvertently create a multicast routing loop
and have a corner case where a multicast frame is
retransmitted a few times too many.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/ieee80211_i.h | 3 ++-
net/mac80211/iface.c | 3 ---
net/mac80211/mesh.c | 56 ++++++++++++++++++++++++++++++--------------
net/mac80211/mesh.h | 7 +++---
net/mac80211/rx.c | 2 +-
5 files changed, 45 insertions(+), 26 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index da7fbd4..a8b33d2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -296,6 +296,7 @@ struct mesh_stats {
* @is_secure: true if the mesh is secure
* @can_share: true if this bss can be shared (user-configurable per-if)
* @net: network namespace devices in this mbss belong to
+ * @rmc: Recent Multicast Cache for this mbss
* @list: listptr for siblings in mesh_bss_list
* @if_list: interfaces sharing this bss
*/
@@ -310,6 +311,7 @@ struct mesh_local_bss {
bool can_share;
struct net *net;

+ struct mesh_rmc *rmc;
struct list_head list;
struct list_head if_list;
};
@@ -598,7 +600,6 @@ struct ieee80211_if_mesh {
unsigned long next_perr;
/* Timestamp of last PREQ sent */
unsigned long last_preq;
- struct mesh_rmc *rmc;
spinlock_t mesh_preq_queue_lock;
struct mesh_preq_queue preq_queue;
int preq_queue_len;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 9daa64e..652fb40 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -994,9 +994,6 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
__skb_queue_purge(&sdata->fragments[i].skb_list);
sdata->fragment_next = 0;

- if (ieee80211_vif_is_mesh(&sdata->vif))
- mesh_rmc_free(sdata);
-
flushed = sta_info_flush(sdata);
WARN_ON(flushed);
}
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 271ddc9..9445f02 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -100,6 +100,11 @@ mesh_bss_create(struct ieee80211_sub_if_data *sdata, struct mesh_setup *setup)
if (!mbss)
return NULL;

+ if (mesh_rmc_init(mbss)) {
+ kfree(mbss);
+ return NULL;
+ }
+
INIT_LIST_HEAD(&mbss->if_list);

mbss->mesh_id_len = setup->mesh_id_len;
@@ -129,6 +134,7 @@ static void mesh_bss_remove(struct ieee80211_sub_if_data *sdata)
/* free when no more devs have this mbss */
if (list_empty(&mbss->if_list)) {
list_del(&mbss->list);
+ mesh_rmc_free(mbss);
kfree(mbss);
}
mutex_unlock(&mesh_bss_mtx);
@@ -360,26 +366,31 @@ void mesh_sta_cleanup(struct sta_info *sta)
ieee80211_mbss_info_change_notify(sdata, changed);
}

-int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
+int mesh_rmc_init(struct mesh_local_bss *mbss)
{
+ struct mesh_rmc *rmc;
int i;

- sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
- if (!sdata->u.mesh.rmc)
+ rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
+ if (!rmc)
return -ENOMEM;
- sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
- for (i = 0; i < RMC_BUCKETS; i++)
- INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i]);
+ rmc->idx_mask = RMC_BUCKETS - 1;
+ for (i = 0; i < RMC_BUCKETS; i++) {
+ INIT_LIST_HEAD(&rmc->bucket[i]);
+ rwlock_init(&rmc->bucket_lock[i]);
+ }
+
+ mbss->rmc = rmc;
return 0;
}

-void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
+void mesh_rmc_free(struct mesh_local_bss *mbss)
{
- struct mesh_rmc *rmc = sdata->u.mesh.rmc;
+ struct mesh_rmc *rmc = mbss->rmc;
struct rmc_entry *p, *n;
int i;

- if (!sdata->u.mesh.rmc)
+ if (!rmc)
return;

for (i = 0; i < RMC_BUCKETS; i++) {
@@ -390,13 +401,12 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
}

kfree(rmc);
- sdata->u.mesh.rmc = NULL;
+ mbss->rmc = NULL;
}

/**
* mesh_rmc_check - Check frame in recent multicast cache and add if absent.
*
- * @sdata: interface
* @sa: source address
* @mesh_hdr: mesh_header
*
@@ -406,18 +416,20 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
* received this frame lately. If the frame is not in the cache, it is added to
* it.
*/
-int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
+int mesh_rmc_check(struct mesh_local_bss *mbss,
const u8 *sa, struct ieee80211s_hdr *mesh_hdr)
{
- struct mesh_rmc *rmc = sdata->u.mesh.rmc;
+ struct mesh_rmc *rmc = mbss->rmc;
u32 seqnum = 0;
- int entries = 0;
+ int entries = 0, ret = 0;
u8 idx;
struct rmc_entry *p, *n;

/* Don't care about endianness since only match matters */
memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
+
+ read_lock(&rmc->bucket_lock[idx]);
list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
++entries;
if (time_after(jiffies, p->exp_time) ||
@@ -425,19 +437,28 @@ int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
list_del(&p->list);
kmem_cache_free(rm_cache, p);
--entries;
- } else if ((seqnum == p->seqnum) && ether_addr_equal(sa, p->sa))
- return -1;
+ } else if ((seqnum == p->seqnum) &&
+ ether_addr_equal(sa, p->sa)) {
+ ret = -1;
+ break;
+ }
}
+ read_unlock(&rmc->bucket_lock[idx]);
+
+ if (ret)
+ return ret;

p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
if (!p)
return 0;

+ write_lock(&rmc->bucket_lock[idx]);
p->seqnum = seqnum;
p->exp_time = jiffies + RMC_TIMEOUT;
memcpy(p->sa, sa, ETH_ALEN);
list_add(&p->list, &rmc->bucket[idx]);
- return 0;
+ write_unlock(&rmc->bucket_lock[idx]);
+ return ret;
}

int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
@@ -1242,7 +1263,6 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
ifmsh->sn = 0;
ifmsh->num_gates = 0;
atomic_set(&ifmsh->mpaths, 0);
- mesh_rmc_init(sdata);
ifmsh->last_preq = jiffies;
ifmsh->next_perr = jiffies;
/* Allocate all mesh structures when creating the first mesh interface. */
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 2f83e8c..bf108ef 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -185,6 +185,7 @@ struct rmc_entry {

struct mesh_rmc {
struct list_head bucket[RMC_BUCKETS];
+ rwlock_t bucket_lock[RMC_BUCKETS];
u32 idx_mask;
};

@@ -209,7 +210,7 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
struct ieee80211s_hdr *meshhdr,
const char *addr4or5, const char *addr6);
-int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
+int mesh_rmc_check(struct mesh_local_bss *mbss,
const u8 *addr, struct ieee80211s_hdr *mesh_hdr);
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *ie);
@@ -228,8 +229,8 @@ int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
-void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
-int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
+void mesh_rmc_free(struct mesh_local_bss *mbss);
+int mesh_rmc_init(struct mesh_local_bss *mbss);
void ieee80211s_init(void);
void ieee80211s_update_metric(struct ieee80211_local *local,
struct sta_info *sta, struct sk_buff *skb);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d86f0df..0c5f870 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2033,7 +2033,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
/* frame is in RMC, don't forward */
if (ieee80211_is_data(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1) &&
- mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
+ mesh_rmc_check(mbss(sdata), hdr->addr3, mesh_hdr))
return RX_DROP_MONITOR;

if (!ieee80211_is_data(hdr->frame_control) ||
--
1.7.10.4


2013-05-07 14:22:20

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC 01/12] mac80211: track and share mesh BSSes among interfaces

On Tue, 2013-05-07 at 10:08 -0400, Bob Copeland wrote:
> On Tue, May 07, 2013 at 03:37:42PM +0200, Johannes Berg wrote:
> > Ok this is big ... Let me tackle it patch by patch I guess :-)
> >
> > > +struct mesh_local_bss {
> >
> > > + bool can_share;
> >
> > Does that even make sense? I mean, wouldn't you simply not link/create
> > such an entry if the given vif can't share?
>
> We could do that, but as written mpath table now wants an mbss pointer
> in either case. Seemed more straight-forward to just always require
> it even though the structures are kind of pointless for unshared vifs.

But why even add it to the global list if you only need it locally?

Anyway I guess it doesn't matter, just seemed a bit odd.

johannes


2013-05-03 02:36:20

by Thomas Pedersen

[permalink] [raw]
Subject: [RFC 05/12] mac80211: forward frames on correct mbss-shared interface

A forwarded frame may have a destination STA which resides
on a vif other than the RX interface. Have
mesh_nexthop_lookup() fill in the right outgoing sdata in
the skb control block.

Also update the congestion detection logic to take into
account a possibly different outgoing interface.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/rx.c | 47 ++++++++++++++++++++++++++++++++---------------
1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4e7886d..d86f0df 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2077,13 +2077,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
ether_addr_equal(sdata->vif.addr, hdr->addr3))
return RX_CONTINUE;

- q = ieee80211_select_queue_80211(sdata, skb, hdr);
- if (ieee80211_queue_stopped(&local->hw, q)) {
- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
- return RX_DROP_MONITOR;
- }
- skb_set_queue_mapping(skb, q);
-
if (!--mesh_hdr->ttl) {
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
goto out;
@@ -2106,21 +2099,45 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.vif = &rx->sdata->vif;
info->control.jiffies = jiffies;
+
+ /* unicast frame may go out on a different HW, so resolve now */
+ if (!is_multicast_ether_addr(fwd_hdr->addr1)) {
+ if (!mesh_nexthop_lookup(mbss, fwd_skb))
+ /* next hop may be on a different interface */
+ local = vif_to_sdata(info->control.vif)->local;
+ else {
+ /* unable to resolve next hop */
+ mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
+ fwd_hdr->addr3, 0, reason,
+ fwd_hdr->addr2);
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh,
+ dropped_frames_no_route);
+ kfree_skb(fwd_skb);
+ return RX_DROP_MONITOR;
+ }
+ }
+
+ /*
+ * note: ifmsh still points to RX iface (for forwarded frame
+ * statistics), while local is sending HW
+ */
+ q = ieee80211_select_queue_80211(vif_to_sdata(info->control.vif),
+ fwd_skb, fwd_hdr);
+ if (ieee80211_queue_stopped(&local->hw, q)) {
+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
+ kfree_skb(fwd_skb);
+ return RX_DROP_MONITOR;
+ }
+ skb_set_queue_mapping(fwd_skb, q);
+
if (is_multicast_ether_addr(fwd_hdr->addr1)) {
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
/* update power mode indication when forwarding */
ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
- } else if (!mesh_nexthop_lookup(mbss, fwd_skb)) {
+ } else {
/* mesh power mode flags updated in mesh_nexthop_lookup */
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
- } else {
- /* unable to resolve next hop */
- mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
- fwd_hdr->addr3, 0, reason, fwd_hdr->addr2);
- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
- kfree_skb(fwd_skb);
- return RX_DROP_MONITOR;
}

IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
--
1.7.10.4