2015-07-03 19:42:15

by Bob Copeland

[permalink] [raw]
Subject: [PATCH v2 0/3] Mesh AID fixes

This patchset corrects the use of peer link id as a stand-in for the
association ID, which is at odds with the standard. Using an incremental
AID generated on the local sta whenever a peer is added enables smaller
TIM elements, and removes one possible source of ambiguity when plids
collide.

Using a proper aid also will make it easier to implement mesh on ath10k.

Because mac80211 currently only implements the buffering side of mesh
power save, we don't need to change any code that reads the AID from
confirm frames. Which is good because it was previously always wrong.

v2: dynamically create the bitmap on demand rather than maintain it

Bob Copeland (3):
mac80211: reorder mesh_plink to remove forward decl
mac80211: mesh: separate plid and aid concepts
mac80211: select an AID when creating new mesh STAs

net/mac80211/cfg.c | 3 +
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mesh.c | 7 +++
net/mac80211/mesh_plink.c | 147 +++++++++++++++++++++++++--------------------
net/mac80211/sta_info.c | 5 +-
5 files changed, 94 insertions(+), 69 deletions(-)

--
2.1.4



2015-07-03 19:42:15

by Bob Copeland

[permalink] [raw]
Subject: [PATCH v2 2/3] mac80211: mesh: separate plid and aid concepts

According to 802.11-2012 13.3.1, a mesh STA should assign an AID
upon receipt of a mesh peering open frame rather than using the link
id of the peer. Using the peer link id has two potential issues:
it may not be unique among the peers, and by its nature it is random,
so the TIM may not compress well.

In preparation for allocating it properly, use sta->sta.aid, but keep
the existing behavior of using the plid.

Additionally, fix a bug where the AID is written into the wrong place
in peering confirm frame skbs.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 20 ++++++++++++--------
net/mac80211/sta_info.c | 5 +----
2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 7b071e36e55e..9dca16bd3eb9 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -200,6 +200,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
}

static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
enum ieee80211_self_protected_actioncode action,
u8 *da, u16 llid, u16 plid, u16 reason)
{
@@ -249,7 +250,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
/* AID */
pos = skb_put(skb, 2);
- put_unaligned_le16(plid, pos + 2);
+ put_unaligned_le16(sta->sta.aid, pos);
}
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@@ -362,7 +363,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
spin_lock_bh(&sta->mesh->plink_lock);
changed = __mesh_plink_deactivate(sta);
sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED;
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_CLOSE,
sta->sta.addr, sta->mesh->llid, sta->mesh->plid,
sta->mesh->reason);
spin_unlock_bh(&sta->mesh->plink_lock);
@@ -619,7 +620,7 @@ static void mesh_plink_timer(unsigned long data)
}
spin_unlock_bh(&sta->mesh->plink_lock);
if (action)
- mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+ mesh_plink_frame_tx(sdata, sta, action, sta->sta.addr,
sta->mesh->llid, sta->mesh->plid, reason);
}

@@ -689,7 +690,7 @@ u32 mesh_plink_open(struct sta_info *sta)
/* set the non-peer mode to active during peering */
changed = ieee80211_mps_local_status_update(sdata);

- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
+ mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_OPEN,
sta->sta.addr, sta->mesh->llid, 0, 0);
return changed;
}
@@ -871,13 +872,13 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
}
spin_unlock_bh(&sta->mesh->plink_lock);
if (action) {
- mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+ mesh_plink_frame_tx(sdata, sta, action, sta->sta.addr,
sta->mesh->llid, sta->mesh->plid,
sta->mesh->reason);

/* also send confirm in open case */
if (action == WLAN_SP_MESH_PEERING_OPEN) {
- mesh_plink_frame_tx(sdata,
+ mesh_plink_frame_tx(sdata, sta,
WLAN_SP_MESH_PEERING_CONFIRM,
sta->sta.addr, sta->mesh->llid,
sta->mesh->plid, 0);
@@ -1067,8 +1068,9 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
goto unlock_rcu;
}
sta->mesh->plid = plid;
+ sta->sta.aid = plid;
} else if (!sta && event == OPN_RJCT) {
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ mesh_plink_frame_tx(sdata, NULL, WLAN_SP_MESH_PEERING_CLOSE,
mgmt->sa, 0, plid,
WLAN_REASON_MESH_CONFIG);
goto unlock_rcu;
@@ -1078,8 +1080,10 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
}

/* 802.11-2012 13.3.7.2 - update plid on CNF if not set */
- if (!sta->mesh->plid && event == CNF_ACPT)
+ if (!sta->mesh->plid && event == CNF_ACPT) {
sta->mesh->plid = plid;
+ sta->sta.aid = sta->mesh->plid;
+ }

changed |= mesh_plink_fsm(sdata, sta, event);

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 9da7d2bc271a..70cd9fa57424 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -635,7 +635,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
bool indicate_tim = false;
u8 ignore_for_tim = sta->sta.uapsd_queues;
int ac;
- u16 id;
+ u16 id = sta->sta.aid;

if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
@@ -643,12 +643,9 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
return;

ps = &sta->sdata->bss->ps;
- id = sta->sta.aid;
#ifdef CONFIG_MAC80211_MESH
} else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
ps = &sta->sdata->u.mesh.ps;
- /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */
- id = sta->mesh->plid % (IEEE80211_MAX_AID + 1);
#endif
} else {
return;
--
2.1.4


2015-07-03 19:42:17

by Bob Copeland

[permalink] [raw]
Subject: [PATCH v2 1/3] mac80211: reorder mesh_plink to remove forward decl

Move mesh_plink_frame_tx() above the first caller to remove
the forward declaration.

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

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 1a7d98398626..7b071e36e55e 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -53,11 +53,6 @@ static const char * const mplevents[] = {
[CLS_IGNR] = "CLS_IGNR"
};

-static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_self_protected_actioncode action,
- u8 *da, u16 llid, u16 plid, u16 reason);
-
-
/* We only need a valid sta if user configured a minimum rssi_threshold. */
static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta)
@@ -204,58 +199,6 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
return BSS_CHANGED_HT;
}

-/**
- * __mesh_plink_deactivate - deactivate mesh peer link
- *
- * @sta: mesh peer link to deactivate
- *
- * All mesh paths with this peer as next hop will be flushed
- * Returns beacon changed flag if the beacon content changed.
- *
- * Locking: the caller must hold sta->mesh->plink_lock
- */
-static u32 __mesh_plink_deactivate(struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata = sta->sdata;
- u32 changed = 0;
-
- lockdep_assert_held(&sta->mesh->plink_lock);
-
- if (sta->mesh->plink_state == NL80211_PLINK_ESTAB)
- changed = mesh_plink_dec_estab_count(sdata);
- sta->mesh->plink_state = NL80211_PLINK_BLOCKED;
- mesh_path_flush_by_nexthop(sta);
-
- ieee80211_mps_sta_status_update(sta);
- changed |= ieee80211_mps_set_sta_local_pm(sta,
- NL80211_MESH_POWER_UNKNOWN);
-
- return changed;
-}
-
-/**
- * mesh_plink_deactivate - deactivate mesh peer link
- *
- * @sta: mesh peer link to deactivate
- *
- * All mesh paths with this peer as next hop will be flushed
- */
-u32 mesh_plink_deactivate(struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata = sta->sdata;
- u32 changed;
-
- spin_lock_bh(&sta->mesh->plink_lock);
- changed = __mesh_plink_deactivate(sta);
- sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED;
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
- sta->sta.addr, sta->mesh->llid, sta->mesh->plid,
- sta->mesh->reason);
- spin_unlock_bh(&sta->mesh->plink_lock);
-
- return changed;
-}
-
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
enum ieee80211_self_protected_actioncode action,
u8 *da, u16 llid, u16 plid, u16 reason)
@@ -375,6 +318,58 @@ free:
return err;
}

+/**
+ * __mesh_plink_deactivate - deactivate mesh peer link
+ *
+ * @sta: mesh peer link to deactivate
+ *
+ * All mesh paths with this peer as next hop will be flushed
+ * Returns beacon changed flag if the beacon content changed.
+ *
+ * Locking: the caller must hold sta->mesh->plink_lock
+ */
+static u32 __mesh_plink_deactivate(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ u32 changed = 0;
+
+ lockdep_assert_held(&sta->mesh->plink_lock);
+
+ if (sta->mesh->plink_state == NL80211_PLINK_ESTAB)
+ changed = mesh_plink_dec_estab_count(sdata);
+ sta->mesh->plink_state = NL80211_PLINK_BLOCKED;
+ mesh_path_flush_by_nexthop(sta);
+
+ ieee80211_mps_sta_status_update(sta);
+ changed |= ieee80211_mps_set_sta_local_pm(sta,
+ NL80211_MESH_POWER_UNKNOWN);
+
+ return changed;
+}
+
+/**
+ * mesh_plink_deactivate - deactivate mesh peer link
+ *
+ * @sta: mesh peer link to deactivate
+ *
+ * All mesh paths with this peer as next hop will be flushed
+ */
+u32 mesh_plink_deactivate(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ u32 changed;
+
+ spin_lock_bh(&sta->mesh->plink_lock);
+ changed = __mesh_plink_deactivate(sta);
+ sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED;
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ sta->sta.addr, sta->mesh->llid, sta->mesh->plid,
+ sta->mesh->reason);
+ spin_unlock_bh(&sta->mesh->plink_lock);
+
+ return changed;
+}
+
static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee802_11_elems *elems, bool insert)
--
2.1.4


2015-07-03 19:42:16

by Bob Copeland

[permalink] [raw]
Subject: [PATCH v2 3/3] mac80211: select an AID when creating new mesh STAs

Instead of using peer link id for AID, generate a new
AID when creating mesh STAs in the kernel peering manager.
This enables smaller TIM elements and more closely follows
the standard, and it also enables mesh to work on drivers
that require a valid AID when the STA is inserted (ath10k
firmware has this requirement, for example).

In the case of userspace-managed stations, we use the AID
from NL80211_CMD_NEW_STATION.

Signed-off-by: Bob Copeland <[email protected]>
---

v2: generate the bitmap as needed inside mesh_allocate_aid rather
than maintaining the whole time (Johannes)

[generating a bitmap is not really required, but I guess it would
be better than a nested loop here.]

net/mac80211/mesh_plink.c | 41 +++++++++++++++++++++++++++++++++++------
1 file changed, 35 insertions(+), 6 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 9dca16bd3eb9..9619159f3dbe 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -421,20 +421,54 @@ out:
spin_unlock_bh(&sta->mesh->plink_lock);
}

+static int mesh_allocate_aid(struct ieee80211_sub_if_data *sdata)
+{
+ struct sta_info *sta;
+ unsigned long *aid_map;
+ int aid;
+
+ aid_map = kcalloc(BITS_TO_LONGS(IEEE80211_MAX_AID + 1),
+ sizeof(*aid_map), GFP_KERNEL);
+ if (!aid_map)
+ return -ENOMEM;
+
+ /* reserve aid 0 for mcast indication */
+ __set_bit(0, aid_map);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sta, &sdata->local->sta_list, list)
+ __set_bit(sta->sta.aid, aid_map);
+ rcu_read_unlock();
+
+ aid = find_first_zero_bit(aid_map, IEEE80211_MAX_AID + 1);
+ kfree(aid_map);
+
+ if (aid > IEEE80211_MAX_AID)
+ return -ENOBUFS;
+
+ return aid;
+}
+
static struct sta_info *
__mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
{
struct sta_info *sta;
+ int aid;

if (sdata->local->num_sta >= MESH_MAX_PLINKS)
return NULL;

+ aid = mesh_allocate_aid(sdata);
+ if (aid < 0)
+ return NULL;
+
sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
if (!sta)
return NULL;

sta->mesh->plink_state = NL80211_PLINK_LISTEN;
sta->sta.wme = true;
+ sta->sta.aid = aid;

sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
@@ -658,8 +692,6 @@ static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata)

do {
get_random_bytes(&llid, sizeof(llid));
- /* for mesh PS we still only have the AID range for TIM bits */
- llid = (llid % IEEE80211_MAX_AID) + 1;
} while (llid_in_use(sdata, llid));

return llid;
@@ -1068,7 +1100,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
goto unlock_rcu;
}
sta->mesh->plid = plid;
- sta->sta.aid = plid;
} else if (!sta && event == OPN_RJCT) {
mesh_plink_frame_tx(sdata, NULL, WLAN_SP_MESH_PEERING_CLOSE,
mgmt->sa, 0, plid,
@@ -1080,10 +1111,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
}

/* 802.11-2012 13.3.7.2 - update plid on CNF if not set */
- if (!sta->mesh->plid && event == CNF_ACPT) {
+ if (!sta->mesh->plid && event == CNF_ACPT)
sta->mesh->plid = plid;
- sta->sta.aid = sta->mesh->plid;
- }

changed |= mesh_plink_fsm(sdata, sta, event);

--
2.1.4


2015-07-09 19:26:15

by Bob Copeland

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] mac80211: select an AID when creating new mesh STAs

On Fri, Jul 3, 2015 at 3:41 PM, Bob Copeland <[email protected]> wrote:
> Instead of using peer link id for AID, generate a new
> AID when creating mesh STAs in the kernel peering manager.

I missed a case where llid was used for aid in
ieee80211_mps_frame_release() -- will send a v3 for the series.

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